Having this code, GCC and MSVC are both happy with it, when clang complains. Any two lambdas must have different types, which makes me think that clang "caches" the type of the default template argument (but only if the class itself is a template).
UPDATE: What I mean here is I expect that every time I instantiate the function template it should infer the type of the default argument. But what truly happens (in the third test) is clang instantiate the function template only once (on the first use). This is is inconsistent not olny with both other major compilers but even with clang itself. As you can see such a behavior only applies if the function template defined/declared in a class template (doesn't matter if class/function template arguments are dependent or not). In other two tests (free function and method in non-class-template) the type is inferencing on each instantiation.
Is there any formal rule for that? Or it's undefined/unspecified/implementation specific behavior?
#include <type_traits>
template <typename T = decltype([](){})>
T f();
struct Test1 {
template <typename T = decltype([](){})>
T f();
};
template <typename = void>
struct Test2 {
template <typename T = decltype([](){})>
T f();
};
int main()
{
static_assert(!std::is_same_v<decltype(f()), decltype(f())>);
Test1 test1;
static_assert(!std::is_same_v<decltype(test1.f()), decltype(test1.f())>);
Test2 test2;
static_assert(!std::is_same_v<decltype(test2.f()), decltype(test2.f())>); // GCC and MSVC ok with this line, clang complains
}
[](){}
is unique, per [expr.prim.lambda.closure]: "The type of a lambda-expression is a unique, unnamed non-union class type." Each occurrence of[](){}
is a distinct type, and clang appears to be correct. It's as if you had writtenstruct L1 { void operator()(){}}; struct L2 { void operator()(){}}; struct L3 { void operator()(){}};
and then usedtemplate<typename T = L1>
forf()
,template<typename T = L2>
forTest1::f()
, andtemplate<typename T = L3>
forTest2::f()
. – Infertilef()
evaluates asf<decltype([]{})>()
(i.e. every call evaluates with a unique lambda) buttest2.f()
evaluates astest2.f<L3>()
(i.e. every call evaluates with the same lambda). The other two compilers evaluate the default argument on the call-site in every case (consistently). – Babirusaf()
andf<decltype([]{})>()
are not the same thing. The first uses the lambda declared on line 3. The second uses the lambda declared inline. The way to understand this is to replace all lambdas with explicitly named types. Create a new explicitly named type for each occurrence of a lambda in the source code. – Infertilef()
in the way you are describing. – Babirusastd::is_same_v<decltype(test1.f()), decltype(test2.f())>)
. My read of the standard is that all three assertions should fail (since the first is asserting that L1!=L1, the second is asserting that L2!=L2, and the third is asserting that L3!=L3. But it seems all three major compilers disagree with me, so I must be misreading something.) – Infertile