Deduce template argument from std::function call signature
Asked Answered
L

3

13

Consider this template function:

template<typename ReturnT>
ReturnT foo(const std::function<ReturnT ()>& fun)
{
    return fun();
}

Why isn't it possible for the compiler to deduce ReturnT from the passed call signature?

bool bar() { /* ... */ }

foo<bool>(bar); // works
foo(bar); // error: no matching function call
Linguistics answered 19/6, 2012 at 14:40 Comment(3)
An answer to one of my previous questions allows this sort of syntax. I hope that helps. It's specialized in case the return type is void too.Peridot
@Peridot Thanks for the hint - I'll try to understand it :)Linguistics
N.B. very similar to https://mcmap.net/q/904540/-c-11-template-function-that-takes-a-std-function-which-depends-of-template-parameters/981959 and https://mcmap.net/q/483577/-c-11-variadic-std-function-parameter/981959, but I think the answers here are clearer for this specific question.Becker
P
8
std::function<bool()> bar;

foo(bar); // works just fine

C++ can't deduce the return type from your function bar because it would have to know the type before it could find all the constructors that take your function pointer.

For example, who's to say that std::function<std::string()> doesn't have a constructor taking a bool (*)()?

Pollypollyanna answered 19/6, 2012 at 15:2 Comment(0)
B
17

A function pointer of type bool (*)() can be converted to std::function<bool()> but is not the same type, so a conversion is needed. Before the compiler can check whether that conversion is possible it needs to deduce ReturnT as bool, but to do that it needs to already know that std::function<bool()> is a possible conversion, which isn't possible until it deduces ReturnT ... see the problem?

Also, consider that bool(*)() could also be converted to std::function<void()> or std::function<int()> ... which should be deduced?

Consider this simplification:

template<typename T>
  struct function
  {
    template<typename U>
      function(U) { }
  };

template<typename T>
  void foo(function<T>)
  { }

int main()
{
    foo(1);
}

How can the compiler know whether you wanted to create function<int> or function<char> or function<void> when they can all be constructed from an int?

Becker answered 19/6, 2012 at 15:3 Comment(0)
P
8
std::function<bool()> bar;

foo(bar); // works just fine

C++ can't deduce the return type from your function bar because it would have to know the type before it could find all the constructors that take your function pointer.

For example, who's to say that std::function<std::string()> doesn't have a constructor taking a bool (*)()?

Pollypollyanna answered 19/6, 2012 at 15:2 Comment(0)
N
1

The function bar is of type bool (*)() or so, that is: a normal pre-C++11 function type. I'm not that confident in C++11, but I guess the compiler does not see the connection between bool (*)() and const std::function<ReturnT()>&, even when the first can be implicitly converted into the second for ReturnT = bool.

Noemi answered 19/6, 2012 at 14:44 Comment(3)
Actually, no matter how the conversion proceeds, the definition of std::function is: template<class R, class... Args> class function<R(Args...)> where R is known to be bool … therefore ReturnT should be deducable for foo, right?Linguistics
@Karl, but std::function has a constructor taking any type, so bool(*)() could also be converted to std::function<void()> or other types - there isn't a single, unique conversion sequence that means only a single std::function specialization can be deducedBecker
@JonathanWakely Okay, think I see it now. Thanks for helping :-)Linguistics

© 2022 - 2024 — McMap. All rights reserved.