【问题标题】:std::function incomplete type on const functionconst 函数上的 std::function 不完整类型
【发布时间】:2020-04-21 09:51:10
【问题描述】:

考虑以下按预期工作的代码:

#include <iostream>
#include <functional>

struct foo
{
    std::function<int()> get;
};

struct bar
{
    int get()
    {
        return 42;
    }
};

int main()
{
    foo f;
    bar b;
    f.get = std::bind(&bar::get, &b);

    if (f.get())
        std::cout << "f.get(): " << f.get() << std::endl;

    return 0;
}

现在,假设 bar::get() 是一个 const 成员函数:

#include <iostream>
#include <functional>

struct foo
{
    std::function<int()const> get;
};

struct bar
{
    int get() const
    {
        return 42;
    }
};

int main()
{
    foo f;
    bar b;
    f.get = std::bind(&bar::get, &b);

    if (f.get())
        std::cout << "f.get(): " << f.get() << std::endl;
}

使用 GCC 9.2,此片段会引发以下编译器错误:

main.cpp:6:31: error: field 'get' has incomplete type 'std::function<int() const>'
    6 |     std::function<int()const> get;
      |                               ^~~
In file included from /usr/local/include/c++/9.2.0/functional:59,
                 from main.cpp:2:
/usr/local/include/c++/9.2.0/bits/std_function.h:128:11: note: declaration of 'class std::function<int() const>'
  128 |     class function;
      |           ^~~~~~~~

我不明白为什么foo::get 的类型不完整。 有人可以指出我理解这种行为并相应地“修复”它的正确方向吗? 我需要将 const 成员函数绑定到函数指针。

【问题讨论】:

  • 所以你想要const std::function&lt;int()&gt; get;?或者你想要int (bar::*get)() const;? constness 在std::bind 而非std::function 进行检查。

标签: c++ c++11 stl std-function


【解决方案1】:

int()const 是一个abominable type

std::function&lt;int()const&gt; 不是类型,因为它与only defined specialisation 不匹配

namespace std {
    template< class R, class... Args >
    class function<R(Args...)> { ... };
}

【讨论】:

    【解决方案2】:

    只需使用std::function&lt;int()&gt;

    const 位只对成员函数有意义。您已经将 bar::get 绑定到实例 b 以将其保存为 std::function

    【讨论】:

      【解决方案3】:

      正如@KamilCuk 所说:

      在 std::bind 中检查常量,而不是在 std::function 中检查

      您不需要将explicit const 传递给std::function。只需使用您的旧原型:std::function&lt;int()&gt;。如果您没有 const 重载(也就是说,您有 int bar::get()int bar::get() const 之一)对于同一个成员函数(否则,您需要显式类型转换),它将起作用。

      实际上,您的函数 (int bar::get() const) 将具有这样的签名(在幕后):

      // int bar::get() const
      int get(const bar *const this)
      {
          return 42;
      }
      
      // int bar::get() 
      int get(bar *const this)
      {
          return 42;
      }
      

      如果你有重载并且想要绑定特定的成员函数,你可以这样做:

      typedef int(bar::*fptr)(void) const; // or remove const
      std::bind((fptr)&bar::get, &b );
      

      看这个:

      #include <iostream>
      #include <functional>
      #include <vector>
      
      struct foo
      {
          std::function<int()> get;
      };
      
      struct bar
      {
          int get()
          {
              return 42;
          }
      
          int get() const
          {
              return 50;
          }
      };
      
      int main()
      {
          foo f;
          bar b;
          typedef int (bar::*fptr)(void);
          typedef int (bar::*fcptr)(void) const;
          f.get = std::bind((fptr)&bar::get, &b);
      
          if (f.get())
              std::cout << "f.get(): " << f.get() << std::endl;
      
          f.get = std::bind((fcptr)&bar::get, &b);
      
          if (f.get())
              std::cout << "f.get(): " << f.get() << std::endl;
      }
      

      输出:

      f.get(): 42
      f.get(): 50
      

      【讨论】:

        【解决方案4】:

        std::bind 不会通过constness 传递给可调用对象。因此,以下将起作用:

        struct foo {
            std::function<int()> get;
            //                 ^ note there is no 'const'
        };
        

        【讨论】:

          猜你喜欢
          • 2019-09-13
          • 1970-01-01
          • 2012-05-30
          • 2014-07-21
          • 2018-03-11
          • 2020-12-25
          • 1970-01-01
          • 2018-11-08
          • 1970-01-01
          相关资源
          最近更新 更多