Can I use the result of a C++17 captureless lambda constexpr conversion operator as a function pointer template non-type argument?

c++, c++17, lambda, language-lawyer, templates

Solution

This is a gcc bug, filed 83258.

In C++14, we used to have a linkage requirement for non-type template parameters of pointer type. But in C++17 (as a result of N4268), the parameter just needs to be a converted constant expression of the correct type, with a few other restrictions (none of which are relevant here). Once we can construct `fp`, we should be able to use it as a template parameter.

Problem

While answering How do I write a lambda expression that looks like a method?, I tried to turn a captureless lambda into a member function pointer by exploiting the fact that, since C++17, captureless lambdas have a constexpr conversion operator to their function pointer type. So I came up with an issue boiling down to: ``` template<void(*)()> struct A{}; int main() { A<static_cast<void(*)()>([]{})>{}; // 1 constexpr auto fp = static_cast<void(*)()>([]{}); A<fp>{}; // 2 } ``` Now, this compiles in clang (since 5.0.0) but gcc(>=7.2) complains: ``` error: lambda-expression in template-argument A<static_cast<void(*)()>([]{ /*whatever*/ })>{}; // 1 ^ error: 'main()::<lambda()>::_FUN' is not a valid template argument for type 'void (*)()' because 'static constexpr void main()::<lambda()>::_FUN()' has no linkage A<fp>{}; // 2 ``` The question is, who's right?

Original source