Глядя на это во второй раз сейчас, и я думаю, что у меня есть правдоподобное объяснение первой ошибки, которую вы видите.
В этом случае более полезно взглянуть на полную ошибку и экземпляры шаблона, которые к ней приводят. Например, ошибка, напечатанная моим компилятором (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 (*)()
Я вернусь к вам, если когда-нибудь выясню вторую ошибку. :)