I have tested these several templates to show the validity of the template instantiation:
template <typename T>
using LRef = T&;
template <typename T>
using Ptr = T*;
template <typename>
requires false
class A {};
// ...
using T0 = LRef<int>; // expected ok
// using T1 = LRef<void>; // expected error, forming void& which is invalid
using T2 = Ptr<void>; // expected ok
// using T3 = Ptr<int&>; // expected error, forming int& * which is invalid
// using T4 = A<int>; // expected error, unsatisfied constraint resulting in invalid instantiation
However,
template <typename T>
struct Box { T value; };
template <typename T, typename U = T>
struct Derive : T, U {};
// ...
using T5 = Derive<int, float>; // unexpected no-error, but should be invalid
// template struct Derive<int, float>; // expected error
using T6 = Derive<Box<int>, Box<float>>; // expected ok
template struct Derive<Box<int>, Box<float>>; // expected ok
using T7 = Derive<Box<int>>; // unexpected no-error, but should be invalid
// template struct Derive<Box<int>>; // expected error
void foo() {
// T5 {}; // error
// T7 {}; // error
}
type alias declarations of T5
and T7
have no error, which are unexpected. I suppose that they should be invalid since the explicit instantiation with the same template arguments and the usage of type alias has errors.
Is this the correct behavior in standard C or just not implemented properly? These 3 major compilers (GCC, Clang, and MSVC) show no compilation error with this program. https://godbolt.org/z/hcbszo49a
CodePudding user response:
Is this valid in standard C or just not implemented properly?
The second snippet without the use of T5{};
and T7{};
is well-formed.
This is because typedef
s, using
and do not require a completely defined type. And from implicit instantiation's documentation:
When code refers to a template in context that requires a completely defined type, or when the completeness of the type affects the code, and this particular type has not been explicitly instantiated, implicit instantiation occurs. For example, when an object of this type is constructed, but not when a pointer to this type is constructed.
(emphasis mine)
And as type alias doesn't require a completely defined type, according to the above quoted statement there will be no implicit instantiation for a typedef
or using
.
For example:
template<typename T> struct C{ T& k;};
using V = C<void>; //no implicit instantiation
int main()
{
C<int>* k;//no implicit instantiation
C<void>* l; //no implicit instantiation
};
They should be invalid since the explicit instantiation with the same template arguments and the usage of type alias has errors.
Note in first snippet where you use an alias template instead of a class template, all compilers seem to produce the error(Demo) you mentioned but this is because they are allowed(but not required) to do so as also explained in Template class compiles with C 17 but not with C 20 if unused function can't be compiled.