The following snippet compiles with no error with Clang 4.0 but GCC 7.0 produces errors (note the use of -std=c++1z flag).
using FuncT = int (*)(double);
template <FuncT FUNC>
int temp_foo(double a)
{
return FUNC(a);
}
int foo(double a)
{
return 42;
}
void func()
{
auto lambda = [](double a) { return 5; };
struct MyStruct
{
static int foo(double a) { return 42; }
};
temp_foo<foo>(3);
temp_foo<static_cast<FuncT>(lambda)>(3);
temp_foo<MyStruct::foo>(3);
}
Specifically, GCC complains that both the lambda and the nested class's method have no linkage, so they can't be used as a non-type template argument.
At least for the lambda case I think that Clang is correct (and GCC is wrong) since (quoting from cppreference, the conversion operator):
The value returned by this conversion function is a pointer to a function with C++ language linkage that, when invoked, has the same effect as invoking the closure object's function call operator directly.
Is GCC misbehaving?
According to http://en.cppreference.com/w/cpp/language/template_parameters#Non-type_template_parameter, it seems like external linkage is no longer a requirement since C++17. The same language is found in the C++17 draft under [temp.arg.nontype] at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf (note that it is incorrectly linked as a C++14 draft).
That link on cppreference also specifically mentions function pointers, pre C++ 17:
Since your question is labelled C++1z (we should probably have a 17 tag by now and use that instead since 17 is finished) we should use the first set of rules. Your example does not seem to fall into any of the exception categories for C++ 17, and therefore gcc is in error.
Note that clang does not compile your example if you change the language flag to 14.
I agree with Nir's answer and wanted to add some information to it. He cites the relevant section in the standard (§14.3.2 [temp.arg.nontype]) that shows that there is no longer a requirement for non-type parameters to have linkage, but that still doesn't show that GCC is misbehaving for the lambda part. For that we need to show that
static_cast<FUNCT>(lambda)
is a converted constant expression. For that we need a newer draft from the one Nir linked. And this section§5.1.5 Lambda expressions [expr.prim.lambda]:
Interestingly enough, GCC claims to have already implemented this (N4268) in the already released version 6 (in case you want to excuse GCC's behavior by saying that GCC 7 hasn't been officially released yet, so maybe when it will come out this will be fixed):
So in summary, this is a bug in GCC.