Deduce template argument from std::function call signature - c++

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

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?

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 (*)()?

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.

Related

Default lambda as templated parameter of a function

Consider the following code
template<bool b, typename T> void foo(const T& t = []() {}) {
// implementation here
}
void bar() {
foo<true>([&](){ /* implementation here */ }); // this compiles
foo<true>(); // this doesn't compile
}
In the case that doesn't compile I get the following errors:
error C2672: 'foo': no matching overloaded function found
error C2783: 'void foo(const T&)': could not deduce template argument for 'T'
I think it's clear what I want to achieve: let foo be called with and without a client-provided lambda. The compiler is MSVC++2017 version 15.4.4 toolset v141.
Default function arguments are not part of the template argument deduction process. To quote [temp.deduct.partial]/3:
The types used to determine the ordering depend on the context in
which the partial ordering is done:
In the context of a function call, the types used are those function parameter types for which the function call has arguments.
141
141) Default arguments are not considered to be arguments in this
context; they only become arguments after a function has been
selected.
That bullet and note indicate that since you didn't provide an argument for t in the call to foo, the type T cannot be deduced. The default lambda argument can only be taken into account if the function is selected to be called, not before.
The solution, as all the others have noted, is to provide an overload without parameters, that will call the templated one with the default lambda you have in mind.
Another (very efficient) way - default T to be a null functor.
// no_op is a function object which does nothing, regardless of how many
// arguments you give it. It will be elided completely unless you compile with
// -O0
struct no_op
{
template<class...Args>
constexpr void operator()(Args&&...) const {}
};
// foo defaults to using a default-constructed no_op as its function object
template<bool b, typename T = no_op> void foo(T&& t = T())
{
// implementation here
t();
}
void bar() {
foo<true>([&](){ std::cout << "something\n"; }); // this compiles
foo<true>(); // this now compiles
}
The compiler uses the arguments passed to deduce the template type. If there's no arguments, then how would the compiler be able to deduce the template type?
You can use overloading instead of default arguments here.
The overloaded non-argument function can simply call the function with the "default" argument:
template<bool b, typename T> void foo(const T& t) {
// implementation here
}
template<bool b> void foo() {
foo<b>([]() {});
}
Consider overloading it directly:
template <bool b>
void foo(void) {
foo([](){});
}
See CppReference:
Non-deduced contexts
4) A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done:
Type template parameter cannot be deduced from the type of a function default argument:
template void f(T = 5, T = 7);
void g()
{
f(1); // OK: calls f<int>(1, 7)
f(); // error: cannot deduce T
f<int>(); // OK: calls f<int>(5, 7)
}
You are trying to say something that makes no sense. You are asking the compiler to guess T from your arguments, but then you do not provide any argument.
The following code does compile, and does what you want:
template<bool b, typename T> void foo(const T& t) {
// implementation here
}
template<bool b> void foo() {
foo<b>([]() {}); // Call actual implementation with empty lambda
}
void bar() {
foo<true>([&](){ /* implementation here */ }); // this compiles
foo<true>(); // this now compiles as well
}

Passing a function with templated parameters as an argument, with function pointers vs. std::function

So I have some generic class with two functions that take functions as parameters. One takes a function pointer and one takes a std::function. Both have a template parameter.
#include <functional>
#include <memory>
namespace {
void example(const std::shared_ptr<const int>&) {}
}
class Generic {
public:
Generic() {}
virtual ~Generic() {}
template <typename Targ>
void doWork(std::function<void(const std::shared_ptr<const Targ>&)> arg) {}
template <typename Targ>
void doWork2(void(*function)(const std::shared_ptr<const Targ>&)) {}
};
class Special : public Generic {
public:
Special() {
//doWork(&example); // Fail!
doWork<int>(&example); // OK!
std::function<void(const std::shared_ptr<const int>&)> func = &example;
doWork(func); // OK!
doWork2(&example); // OK!
}
};
int main(int argc, char** argv) {
Special special;
return 0;
}
With the function pointer it compiles, but with the std::function it does not. Why does template deduction fail here?
Clang reports:
example.cpp:27:9: error: no matching member function for call to 'doWork'
doWork(&example);
^~~~~~
example.cpp:14:10: note: candidate template ignored: could not match 'function<void (const shared_ptr<const type-parameter-0-0> &)>' against 'void (*)(const std::shared_ptr<const int> &)'
void doWork(std::function<void(const std::shared_ptr<const Targ>&)> arg) {
^
1 error generated.
Template argument deduction does not work like that.
Template argument deduction is a pattern match. Is example an object of type std::function<void(const std::shared_ptr<const Targ>&)> for some type Targ?
Not convertible-to, but actually an object of that type already?
No, it is not.
It is, however, already a function pointer (using the implicit decay rules).
There is a C++17 feature that involve deducing template arguments from constructor types; std::function may or may not be instrumented to learn its own type from a function pointer when C++17 or C++20 comes out in this situation. I lack expertise in C++17 to be certain.
This happens because the constructor can't deduce the type of its class. If my wording sounds weird, perhaps this example will help:
template <class T>
class Example {
Example(const T&) { /*...*/ }
};
If I have a function template, such as template <class T> void f(const Example<T>&), I can't just do f(10). This is what your code boils down to. std::function can't know its template parameters based on what you passed to its (non-explicit) constructor.
Note: this is, by the way, in the works for C++17.

std::function cannot deduce overloaded type in template instance

I have this fairly simple template class :
template <typename Value>
struct Foo {
typedef Value ValueType;
Value array[3];
};
Now I am trying to get a function object (std::function) from a simple function using the dependent type of F as function argument and return types.
template <typename F>
void floorfunc(const F& foo) {
typedef typename F::ValueType Value;
auto fptr = std::function<Value(Value)>(std::floor);
}
The compiler correctly instantiates the Value types but fails to guess the correct function overload of floor, and sends me this error message
error: no matching function for call to 'std::function<float(float)>::function(<unresolved overloaded function type>
How do I tell the compiler wich overload needs to be used in that case ?
Add a cast:
std::function<Value(Value)>(static_cast<Value(&)(Value)>(std::floor))
std::floor is overloaded, and the constructor of std::function is a template, so there's no obvious choice of overload and you have to specify it explicitly, which you can do with the cast.

Strange use of void in c++ code

Here is some code from a presentation about async tasks in C++
template <class T> class Future<T>{
//something
void foo(std::function<void(T)> cb);
//something
};
What does void(T) mean?
What does void(T) mean?
That specifies a function type; specifically, a function taking a single parameter of type T, and returning nothing. In general, type specifiers for complex types look like their corresponding variable declarations, but without a variable name:
void f(T); // declare a function
void(T) // specifier for a function type
int a[42]; // declare an array
int[42] // specifier for an array type
In this case, the function type is used to specify the signature of the function-call operator of the std::function:
void operator()(T);
so that the function object can be used like a function with that type:
T some_t;
cb(some_t); // usable like a function taking `T`
cb is a std::function whose operator() takes a T and returns void.
void(T) is a function signature (type)
Note the signature is not a pointer to a function, not a pointer to a member function and no lambda:
#include<functional>
void a(int) {}
struct B {
void f(int) {}
};
int main() {
std::function<void(int)> fn;
fn = a;
B b;
fn = std::bind(&B::f, b, std::placeholders::_1);
auto lambda = [](int) {};
fn = lambda;
}
The explanation can be as follows based on the C++11 specifications : A parameter list consisting of a single unnamed parameter of non-dependent type void is equivalent to an empty parameter list.
void is not a valid argument type for a function, however T in void(T) is a dependent type, it depends on a template parameter. That way you can have no arguments in the function based on the parameter of the template.

function-pointers and class-templates

I have a template class CFoo using the following types
enum My_Types {t1,t2};
with the specialization given by
template<My_Types T>
class CFoo
{
public:
CFoo()
{
std::cerr<<"ERROR:....";
exit(1);
}
};
template<>
class CFoo<t1>
{
....
};
In addition I have a function which uses a CFoo object as an argument
template<class T>
void foo1 ( const T &CfooObj,...);
Now I need a pointer to foo1, so I have to specify the template argument
void (*foo1_pointer) ( const CFoo< t1 >&,...);
But the following seems not to be correct (" no matches converting function foo1..."):
foo1_pointer=&foo1;
How to pass the pointer of this template function correctly?
This is probably due to the old version of your GCC compiler. This code compiles fine on GCC 4.7.2, Clang 3.2, ICC 13.0.1, and VS10:
#include <iostream>
enum My_Types {t1,t2};
template<My_Types T>
class CFoo { /* ... */ };
template<> class CFoo<t1> { /* ... */ };
template<class T>
void foo1 (const T &, ...) { /* ... */ }
int main()
{
void (*foo1_pointer) (const CFoo< t1 >&, ...);
foo1_pointer = &foo1;
}
The compiler should be able to deduce the template arguments of foo1 when taking its address from the type of the function pointer it is assigned to. Per Paragraph 14.8.2.3/1 of the C++11 Standard:
Template arguments can be deduced from the type specified when taking the address of an overloaded function (13.4). The function template’s function type and the specified type are used as the types of P and A, and the deduction is done as described in 14.8.2.5.
And also, per Paragraph 13.4/1:
A use of an overloaded function name without arguments is resolved in certain contexts to a function, a pointer to function or a pointer to member function for a specific function from the overload set. A function template name is considered to name a set of overloaded functions in such contexts. The function selected is the one whose type is identical to the function type of the target type required in the context. [...]
The assignment should be like this:
foo1_pointer = &foo1<CFoo<t1>>;
You can just write foo1<CFoo<t1>>. Or just foo1 (works with g++ 4.7.2).