GCC cannot deduce auto return type from a template function?
Asked Answered
E

1

8

I've a simple template function do_something which returns an integer: 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;
}

With GCC 6.1.1, I get this error:

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);

As you can see, the compiler cannot deduce the result type of the function.

Note that: clang++ 3.8.0 can compile that without any errors.

So my question: is there a way to specify the expected return value from a template function like in this case?

Eshman answered 4/7, 2016 at 0:9 Comment(9)
Use the trailing return type if it depends on one of your parameter arguments.Humoresque
What compiler flags did you use? Did you try -std=c++14?Grouping
Obviously I've compiled with the flag -std=c++14Eshman
@BiagioFesta I find when reading questions here on SO after a while very little seems "obvious" ;)Grouping
gcc will compile the following: auto f=do_something<int>; std::function<int(void)> function = std::bind(f, 12);. However, I do not have sufficient language-lawyer-fu to be able to authoritatively state whether this is a gcc bug, or how these dominoes fall, with respect to the C++ spec.Freund
@Grouping Yeah you're right! I simply mean the compiler should raise an error for bad syntax in case you use 14-STD without that flag.Eshman
@KerrekSB Interesting. Even if this is not what the OP wants, note that using the lambda std::function<int(void)> function = [](){ return do_something(42); }; forces the instantiation and solves the issue. Waiting for a language lawyer...Jamnis
@KerrekSB That quote's limited to class templates.Tyika
@T.C.: Oh right, it does. Never mind.Syblesybley
B
1

It looks like the compiler isn't sure about the type of the do_something<int> - and I'm not sure if this is a compiler issue, or a language issue - but you can force the compiler to get its types sorted out by using do_something<int> in a relatively trivial way before hand. For example the following compiles OK with both gcc and clang trunk versions (according to 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;
}
Battery answered 10/10, 2018 at 1:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.