std :: function неполного типа в константной функции - PullRequest
3 голосов
/ 21 апреля 2020

Рассмотрим следующий код, который работает должным образом:

#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() является функцией-константой:

#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;
}

Использование G CC 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 с указателем на функцию.

Ответы [ 4 ]

3 голосов
/ 21 апреля 2020

int()const является отвратительным типом .

std::function<int()const> не является типом, поскольку он не соответствует только определенной специализации

namespace std {
    template< class R, class... Args >
    class function<R(Args...)> { ... };
}
2 голосов
/ 21 апреля 2020

Просто используйте std::function<int()>.

Бит const имеет смысл только для функций-членов. Вы уже связали bar::get с экземпляром b, чтобы сохранить его как std::function.

1 голос
/ 21 апреля 2020

Как упомянуто @KamilCuk:

Константность проверяется в std :: bind, а не в std :: function

Вам не нужно передавать explicit const to std::function. Просто используйте ваш старый прототип: std::function<int()>. Это будет работать, если у вас нет константной перегрузки (это означает, что у вас есть один из этих int bar::get() или int bar::get() const) для одной и той же функции-члена (В противном случае вам нужно набрать explicity).

На самом деле ваша функция (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;
}

Если у вас есть перегрузки и вы хотите связать указанную c функцию-член, вы можете сделать как то так:

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
1 голос
/ 21 апреля 2020

std::bind не проходит через const ness для вызова. Таким образом, будет работать следующее:

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