Created on 2023-04-19.00:00:00 last changed 3 days ago
Additional notes (January, 2025)
Another example:
template<typename T, typename F = decltype([](){} )> struct Type {}; template<typename A> using C = Type<A>; static_assert(std::same_as<Type<int>,Type<int>>); // #1 static_assert(std::same_as<C<int>,C<int>>); // #2
All of clang, EDG, gcc, and MSVC reject #1; clang additionally rejects #2.
There is also implementation divergence for the following example:
template<typename T> using A = decltype([]{});
template<typename T> void f(A<T>) {}
template<typename T> void f(A<T>) {} // Duplicate definition?
MSVC and gcc reject as a redefinition; clang and EDG accept. Even if only a single definition is present, implementations differ about whether f has internal or external linkage and what properties the mangled name has.
Issue 1979 is related and suggests to treat simple alias templates differently (those would not have specializations, but be transparent for template argument deduction) from more complicated ones (those would have specializations and be morally equivalent to a struct with a member typedef).
Consider:
template<class T> using A = decltype([]{}); static_assert(std::same_as<A<int>, A<int>>);
There is implementation divergence: GCC and MSVC accept, clang rejects. A similar question arises if token-identical alias templates appear in different translation units:
// appearing in multiple translation units
template<typename T> using A = decltype([]{});
inline A<int> f() { return {}; }
An alias template is a templated entity per 13.1 [temp.pre] paragraph 8.1, thus it is a definable item (6.3 [basic.def.odr] paragraph 1.5) and thus there is effectively only a single definition of it (6.3 [basic.def.odr] paragraph 15).
However, that reasoning does not address the question whether A<int> denotes the same type when it appears repeatedly in the same translation unit. Consider 13.7.7.2 [temp.over.link] paragraph 5:
Two lambda-expressions are never considered equivalent.
and 13.7.8 [temp.alias] paragraph 2
When a template-id refers to the specialization of an alias template, it is equivalent to the associated type obtained by substitution of its template-arguments for the template-parameter s in the defining-type-id of the alias template.
This means that a template-id referring to an alias template performs a fresh substitution each time it appears. There is no concept of instantiating an alias template to produce an alias declaration. Subclause 13.7.8 [temp.alias] paragraph 5 specifies:
The type of a lambda-expression appearing in an alias template declaration is different between instantiations of that template, even when the lambda-expression is not dependent.
The outcome seems unfortunate; the first example ought to be well-formed.
History | |||
---|---|---|---|
Date | User | Action | Args |
2025-01-20 16:12:26 | admin | set | messages: + msg7948 |
2023-04-19 00:00:00 | admin | create |