This code works perfectly fine with gcc/g++ and msvc but not with clang. It keeps complaining that no matching function for Log was found, what is going on?
#include <iostream>
template <typename Function, typename... Args>
auto Call(Function func, Args&&... args) -> typename std::result_of<Function&(Args&&...)>::type
{
return func(std::forward<Args>(args)...);
}
template <typename T, typename... Args>
T (*Log( T (*FuncPtr)(Args...) ))(Args...)
{
return FuncPtr;
}
int main()
{
auto r = Log(Call<int(int), int>)([](int x){
return x*10;
}, 10);
std::cerr << r << std::endl;
}
Error:
> error: no matching function for call to 'Log'
> auto r = Log(Call<int(int), int>)([](int x){
> ^~~ test7.cpp:15:5: note: candidate template ignored: couldn't infer template argument 'T' T (*Log( T (*FuncPtr)(Args...)
> ))(Args...)
> ^ 1 error generated.
1 Answer 1
I believe that this code is incorrect. The function parameter to Log cannot be used for template argument deduction in this case because the argument is a non-deduced context.
From [temp.deduct.type] in the standard, p5 lists the non-deduced contexts, and p5.5 says:
A function parameter for which argument deduction cannot be done because the associated function argument is a function, or a set of overloaded functions (13.4), and one or more of the following apply:
and p5.5.3 says:
the set of functions supplied as an argument contains one or more function templates.
My interpretation is that you have a function parameter for which the function argument is a (pointer to) a function and that function is a function template.
Arguably, because this isn't an overload set, this might be something that could be allowed in the future, but I read the standard as not guaranteeing that this technique will work.
auto call = Call<int(int), int>;fails witherror: variable 'call' with type 'auto' has incompatible initializer of type '<overloaded function type>'. The issue withLogis a red herring, the problem starts earlier - the compiler seems to have trouble figuring out what typeCall<int(int), int>is.result_ofdance withdecltype(func(args...))std::result_of<Function &( ...)>? That looks out of place to me.typename std::result_of<...>::typewithstd::result_of_t<...>and clang compiles it. That's... weird.