GCC не может вывести тип автоматического возврата из функции шаблона?

У меня есть простая шаблонная функция do_something, которая возвращает целое число: 123.

template<typename T>
auto do_something(T input) {
  std::this_thread::sleep_for(std::chrono::seconds(1));
  return 123;
}

int main(int argc, char *argv[]) {
  std::function<int(void)> function = std::bind(do_something<int>, 12);
  function();
  return 0;
}

С GCC 6.1.1 я получаю эту ошибку:

test.cpp: In function ‘int main(int, char**)’:
test.cpp:16:70: error: no matching function for call to ‘bind(<unresolved overloaded function type>, int)’
   std::function<int(void)> function = std::bind(do_something<int>, 12);
                                                                      ^
In file included from /usr/include/c++/6.1.1/thread:39:0,
                 from test.cpp:4:
/usr/include/c++/6.1.1/functional:1331:5: note: candidate: template<class _Func, class ... _BoundArgs> typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...)
     bind(_Func&& __f, _BoundArgs&&... __args)
     ^~~~
/usr/include/c++/6.1.1/functional:1331:5: note:   template argument deduction/substitution failed:
test.cpp:16:70: note:   couldn't deduce template parameter ‘_Func’
   std::function<int(void)> function = std::bind(do_something<int>, 12);
                                                                      ^
In file included from /usr/include/c++/6.1.1/thread:39:0,
                 from test.cpp:4:
/usr/include/c++/6.1.1/functional:1359:5: note: candidate: template<class _Result, class _Func, class ... _BoundArgs> typename std::_Bindres_helper<_Result, _Func, _BoundArgs>::type std::bind(_Func&&, _BoundArgs&& ...)
     bind(_Func&& __f, _BoundArgs&&... __args)
     ^~~~
/usr/include/c++/6.1.1/functional:1359:5: note:   template argument deduction/substitution failed:
test.cpp:16:70: note:   couldn't deduce template parameter ‘_Result’
   std::function<int(void)> function = std::bind(do_something<int>, 12);

Как видите, компилятор не может вывести тип результата функции.

Обратите внимание, что clang++ 3.8.0 может скомпилировать это без каких-либо ошибок.

Итак, мой вопрос: есть ли способ указать ожидаемое возвращаемое значение из функции шаблона, как в этом случае?


person BiagioF    schedule 04.07.2016    source источник
comment
Используйте завершающий тип возвращаемого значения, если он зависит от одного из ваших аргументов параметра.   -  person user2296177    schedule 04.07.2016
comment
Какие флаги компилятора вы использовали? Вы пробовали -std=c++14?   -  person Galik    schedule 04.07.2016
comment
Очевидно, я скомпилировал с флагом -std=c++14.   -  person BiagioF    schedule 04.07.2016
comment
@BiagioFesta Я обнаружил, что, читая вопросы здесь, на SO, через некоторое время очень мало что кажется очевидным;)   -  person Galik    schedule 04.07.2016
comment
gcc скомпилирует следующее: auto f=do_something<int>; std::function<int(void)> function = std::bind(f, 12);. Тем не менее, у меня недостаточно language-lawyer-fu, чтобы авторитетно заявить, является ли это ошибкой gcc или тем, как эти домино падают, относительно спецификации C++.   -  person Sam Varshavchik    schedule 04.07.2016
comment
@Galik Да, ты прав! Я просто имею в виду, что компилятор должен выдать ошибку из-за неправильного синтаксиса, если вы используете 14-STD без этого флага.   -  person BiagioF    schedule 04.07.2016
comment
@KerrekSB Интересно. Даже если это не то, чего хочет OP, обратите внимание, что использование лямбда-выражения std::function<int(void)> function = [](){ return do_something(42); }; вызывает создание экземпляра и решает проблему. В ожидании языкового юриста...   -  person skypjack    schedule 04.07.2016
comment
@KerrekSB Эта цитата ограничена шаблонами классов.   -  person T.C.    schedule 04.07.2016
comment
@T.C.: О да, это так. Не берите в голову.   -  person Kerrek SB    schedule 04.07.2016


Ответы (1)


Похоже, что компилятор не уверен в типе do_something<int> - и я не уверен, является ли это проблемой компилятора или проблемой языка, но вы можете заставить компилятор отсортировать свои типы, используя do_something<int> в относительно тривиальный способ заранее. Например, следующий код нормально компилируется как с gcc, так и с clang trunk-версиями (согласно godbolt).

#include <functional>

template<typename T>
auto do_something(T input) {
  return 123;
}

// Make the compiler workout the type of do_something<int> so we can use it later.
auto f = do_something<int>;

int main(int argc, char *argv[]) {
  std::function<int(void)> function = std::bind(do_something<int>, 12);
  function();
  return 0;
}
person Michael Anderson    schedule 10.10.2018