std::function const 函数的类型不完整

std::function incomplete type on const function

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

#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 的类型不完整。 有人可以指出我理解这种行为的正确方向并相应地 "fixing" 吗? 我需要绑定一个 const 成员函数到一个函数指针。

只需使用 std::function<int()>.

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

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

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

如@KamilCuk 所述:

The constness is checked at std::bind, not at std::function

您不需要将 explicit const 传递给 std::function。只需使用您的旧原型:std::function<int()>。如果您没有 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

int()const 是一个 abominable type

std::function<int()const> 不是类型,因为它不匹配 only defined specialisation

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