Вложенный связывают выражения

Это - последующий вопрос моему предыдущему вопросу.

#include 

int foo(void) {return 2;}

class bar {
public:
    int operator() (void) {return 3;};
    int something(int a) {return a;};
};

template  auto func(C&& c) -> decltype(c()) { return c(); }

template  int doit(C&& c) { return c();}

template  void func_wrapper(C&& c) { func( std::bind(doit, std::forward(c)) ); }

int main(int argc, char* argv[])
{
    // call with a function pointer
    func(foo);
    func_wrapper(foo);  // error

    // call with a member function
    bar b;
    func(b);
    func_wrapper(b);

    // call with a bind expression
    func(std::bind(&bar::something, b, 42));
    func_wrapper(std::bind(&bar::something, b, 42)); // error

    // call with a lambda expression
    func( [](void)->int {return 42;} );
    func_wrapper( [](void)->int {return 42;} );

    return 0;
}

Я получаю ошибки компиляции глубоко в заголовках C++:

functional:1137: error: invalid initialization of reference of type ‘int (&)()’ from expression of type ‘int (*)()’
functional:1137: error: conversion from ‘int’ to non-scalar type ‘std::_Bind(bar, int)>’ requested

func_wrapper (нечто), как предполагается, выполняет func (мелкая монета (нечто)). В реальном коде это упаковывает функцию для потока для выполнения. func был бы функция, выполняемая другим потоком, мелкая монета находится промежуточная, чтобы проверить на необработанные исключения и вымыться. Но дополнительные связывают в func_wrapper, портит вещи...

13
задан Community 23 May 2017 в 12:04
поделиться

1 ответ

Глядя на это во второй раз, я думаю, что у меня есть правдоподобное объяснение первой ошибки, которую вы видите.

В этом случае более полезно посмотреть на полную ошибку и экземпляры шаблонов, которые привели к ней. Ошибка, напечатанная моим компилятором (GCC 4.4), например, заканчивается следующими строками:

test.cpp:12:   instantiated from ‘decltype (c()) func(C&&) [with C = std::_Bind<int (*(int (*)()))(int (&)())>]’
test.cpp:16:   instantiated from ‘void func_wrapper(C&&) [with C = int (&)()]’
test.cpp:22:   instantiated from here
/usr/include/c++/4.4/tr1_impl/functional:1137: error: invalid initialization of reference of type ‘int (&)()’ from expression of type ‘int (*)()’

Теперь, глядя на это снизу вверх, фактическое сообщение об ошибке кажется правильным; типы, выведенные компилятором , несовместимы .

Первый экземпляр шаблона, на func_wrapper , ясно показывает, какой тип компилятор вывел из фактического параметра foo в func_wrapper (foo) . Я лично ожидал, что это будет указатель на функцию, но на самом деле это ссылка на функцию .

Второй экземпляр шаблона плохо читается. Но немного поигравшись с std :: bind , я узнал, что формат текстового представления, которое GCC печатает для функтора связывания, примерно такой:

std::_Bind<RETURN-TYPE (*(BOUND-VALUE-TYPES))(TARGET-PARAMETER-TYPES)>

Итак, разрывая его на части:

std::_Bind<int (*(int (*)()))(int (&)())>
// Return type: int
// Bound value types: int (*)()
// Target parameter types: int (&)()

Вот где несовместимые типы начинаются. Очевидно, хотя c в func_wrapper является ссылкой на функцию, она превращается в указатель функции , однажды переданный в std :: bind , что приводит к несовместимости типов. Как бы то ни было, std :: forward в данном случае не имеет значения.

Я считаю, что std :: bind , похоже, заботится только о значениях, а не о ссылках. В C / C ++ нет такого понятия, как значение функции; там только ссылки и указатели. Поэтому, когда ссылка на функцию разыменована, компилятор может только осмысленно дать вам указатель на функцию.

Единственное, что вы можете контролировать, - это параметры вашего шаблона.Вам нужно будет сообщить компилятору, что вы имеете дело с указателем функции с самого начала , чтобы это сработало. В любом случае, вероятно, это то, что вы имели в виду. Для этого явно укажите тип, который вы хотите для параметра шаблона C :

func_wrapper<int (*)()>(foo);

Или, более краткое решение, явно возьмите адрес функции:

func_wrapper(&foo); // with C = int (*)()

Я вернусь к вам, если я когда-нибудь выяснить вторую ошибку. :)

2
ответ дан 2 December 2019 в 02:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: