C++ Inheriting from Undefined Template Type - c++

This code:
template <class T>
class Foo {};
typedef Foo<void*> Bar;
template <class T>
class Foo<T*> : public Bar {};
// use Foo<int*> somewhere.
Compiles and works fine in MSVC 9.0, but doesn't compile in GCC 4.1.1 or GCC 4.3.4, with the error:
error: invalid use of undefined type 'class Bar'
Is this illegal C++ that MSVC accepts incorrectly, or a limitation of GCC?
Either way, how can I work around this get the desired behaviour: pointer specialisations of Foo that inherit from unspecialised Foo<void*>?

You cannot do that, except by writing the specialization for all T*, except when T is void. Otherwise, you will derive the class from itself, which for obvious reasons can't work.
Instantiating the primary class template for arguments that have an explicit or partial specialization is not possible. If you try to, by provoking an instantiation before the explicit or partial specialization is visible (note that your code did not provoke such an instantiation), your program is ill-formed, with no diagnostic being required (which effectively renders the behavior undefined).
To achieve the above work-around, you can use SFINAE
template <class T>
struct isnt_void { typedef void type; };
template<> struct isnt_void<void> { };
template <class T, class = void>
class Foo {};
template <class T>
class Foo<T*, typename isnt_void<T>::type> : public Foo<void*> {};

The typedef is a red herring.
The following code is equivalent:
template <class T>
class Foo {};
template <class T>
class Foo<T*> : public Foo<void*> {};
It should be clear that, although Foo<T*> is declared at this point, it is not defined. And thus you may not use it as a base.
[class.name] (2003 wording, 9.1/2):
A class definition introduces the class name into the scope where it is defined
[class.mem] (2003 wording, 9.2/2):
A class is considered a
completely-defined object type (3.9)
(or complete type) at the closing } of
the class-specifier. Within the class
member-specification, the class is
regarded as complete within function
bodies, default arguments and
constructor ctor-initializers
(including such things in nested
classes). Otherwise it is regarded as
incomplete within its own class
member-specification.
[class.derived] (2003 wording, 10/1):
The class-name in a base-specifier shall not be an incompletely defined class (clause 9);

A superior solution would be to compose of Foo<void*>. After all, you don't want the raw void* interface cluttering up your stuff, and you don't want a Foo<T*> to be convertible to a Foo<void*>.
Alternatively, you could fully specialize Foo<void*> beforehand.
Assuming, of course, that you're doing this for type folding, instead of because you actually want inheritance.

Related

Class template inheriting from incomplete class

This code fails to compile because of the inheritance from an incomplete type (https://godbolt.org/z/G35wj9):
template<typename>
class Incomplete;
class T : public Incomplete<T> {};
template<typename>
class Incomplete {};
int main()
{
[[maybe_unused]] T x;
}
I believed that this rule also applied to class templates. However, this code compiles fine (https://godbolt.org/z/cU6GNt):
template<typename>
class Incomplete;
template<int d>
class T : public Incomplete<T<d>> {};
template<typename>
class Incomplete {};
int main()
{
[[maybe_unused]] T<1> x;
}
When class templates are involved, is the base class only required to be complete at the point of instantiation?
When class templates are involved, is the base class only required to be complete at the point of instantiation?
If it's a dependent base then yes. By that virtue a compiler has no idea what Incomplete<T<d>> is at the point of template definition. After all, for some values of d we can have ourselves a specialization of Incomplete<T<d>> that is entirely different from the primary template declaration.
template<>
class Incomplete<T<0>> {};
This is not a circular dependency. Simply naming the specialization T<0> does not cause it to be instantiated. It's just a type name. But it does mean the compiler has no recourse but wait until it can check the base class is valid.
On the other hand, if the base class is not a dependent type, then using it as base would be ill-formed.
The standard covers this in [temp.inst] §1 (taken from C++17) :
Unless a class template specialization has been explicitly instantiated (17.7.2) or explicitly specialized (17.7.3), the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely-defined object type or when the completeness of the class type affects the semantics of the program. [ Note: In particular, if the semantics of an expression depend on the member or base class lists of a class template specialization, the class template specialization is implicitly generated. For instance, deleting a pointer to class type depends on whether or not the class declares a destructor, and a conversion between pointers to class type depends on the inheritance relationship between the two classes involved. — end note ] [ Example:
template<class T> class B { /* ... */ };
template<class T> class D : public B<T> { /* ... */ };
void f(void*);
void f(B<int>*);
void g(D<int>* p, D<char>* pp, D<double>* ppp) {
f(p); // instantiation of D<int> required: call f(B<int>*)
B<char>* q = pp; // instantiation of D<char> required: convert D<char>* to B<char>*
delete ppp; // instantiation of D<double> required
}
— end example ] If a class template has been declared, but not defined, at the point of instantiation (17.6.4.1), the instantiation yields an incomplete class type (6.9). [ Example:
template<class T> class X;
X<char> ch; // error: incomplete type X<char>
— end example ] [ Note: Within a template declaration, a local class (12.4) or enumeration and the members of a local class are never considered to be entities that can be separately instantiated (this includes their default arguments, noexcept-specifiers, and non-static data member initializers, if any). As a result, the dependent names are looked up, the semantic constraints are checked, and any templates used are instantiated as part of the instantiation of the entity within which the local class or enumeration is declared. — end note ]
Also covered on cppreference.
Just keep in mind that a class template is not a type, and no code is generated for it. Code is generated when the template is instantiated. When a class template is instantiated (implicitly or explicitly), an actual class (type) is generated (including the code for it).
The only difference is, that in your example you use the Incomplete class inside of a template.
In the original example it was used by a class. The type of the class will be created by the compiler at this time, thus before Incomplete is defined.
In your code, Incomplete is used in another template T, (roughly speaking: T is a mold to generate various types by use of Incomplete). At this time the compiler does nothing, it just stores a "rule to generate types" (what I called the mold).
The compiler checks validity of T at the time it is used, hence at the line - then the actual type T<1> : public Incomplete gets generated.
T (the mold) is "valid" iff Incomplete is defined
[[maybe_unused]] T<1> x;
At this point the template class Incomplete is well defined, and the compiler is happy.

Static assert in template specialization fails even if it is not instantiated

The following code compiles fine:
#include <type_traits>
template <typename T> struct dependent_true : std::true_type { };
template <typename T> struct dependent_false : std::false_type { };
template <bool B = false>
class X { static_assert(dependent_false<X>::value); };
template <>
class X<true> { static_assert(dependent_true<X>::value); };
int main() {
X<true> x;
}
That is, the static_assert in the primary template is not evaluated. On the contrary, if I switch to:
template <bool B = false>
class X { static_assert(dependent_true<X>::value); };
template <>
class X<true> { static_assert(dependent_false<X>::value); };
int main() {
X<false> x;
}
Then, the static assertion in template specialization fails, even if it is not instantiated. I just wonder why. I observed this behavior with GCC 8 and Clang 6 (-std=c++17).
Live demo: https://wandbox.org/permlink/MOWNLnGMgmuDA2Ht
template <> class X<true> {/* ... */}; - is not a template anymore.
[temp.expl.spec]/5
A member of an explicitly specialized class is not implicitly
instantiated from the member declaration of the class template;
instead, the member of the class template specialization shall itself
be explicitly defined if its definition is required. In this case, the
definition of the class template explicit specialization shall be in
scope at the point at which the member is defined. The definition of
an explicitly specialized class is unrelated to the definition of a
generated specialization. That is, its members need not have the same
names, types, etc. as the members of a generated specialization.
Members of an explicitly specialized class template are defined in the
same manner as members of normal classes, and not using the template<>
syntax. The same is true when defining a member of an explicitly
specialized member class. However, template<> is used in defining a
member of an explicitly specialized member class template that is
specialized as a class template.
The specialization is just like a regular class. It's not a template, and nothing is dependent. Therefore dependent_false<X>::value is just a constant expression that evaluates immediately to false. So the static assertion is immediately triggered.
Even non-instantiated template parts should be valid C++ code. static_assert(false) makes the program ill-formed. So you have your specialization with static_assert which is known on compile time to be false and your program becomes ill-formed. You have no non-resolved template parameters on your class which is used in static_assert to make compiler wonder; it knows exactly that it is false.
The same goes to if constexpr, you also can't use static_assert with expressions known to be false even if the part where this static_assert is located always gets discarded.

Is it legal to perform partial in-class specialization of a member template class in derived class

It is continuation of this question. I am specifically interested if the partial specialization of a member class like this:
struct FooParent {
template <class>
struct Bar{ };
};
struct Foo: FooParent {
template <class T>
struct Bar<T*> {};
};
I know this can be done inside a namespace scope:
template <class T>
struct Foo::Bar<T*>{ };
But I'm also specifically interested in in-class partial specialization at the level of derived class.
Both clang and gcc complains when encounter a former:
clang states that there is an explicit template specialization which obviously does not occur:
error: explicit specialization of 'Bar' in class scope
gcc is a little bit less verbose here and says that the specialization of the member template must be performed at a namespace scope which obviously is not a case for not derived class.
error: specialization of 'template struct FooParent::Bar' must appear at namespace scope
Is gcc right here in his error message?
I'm trying to sum up what I said in the comments to the question, as requested by the OP.
I guess [temp.class.spec]/5 is enough to reply to the question.
In particular:
A class template partial specialization may be declared or redeclared in any namespace scope in which the corresponding primary template may be defined [...].
In this case, what actually rule on it is where the primary template can be defined.
In the example, you are trying to declare (and contextually define, but it's first of all a declaration) a partial specialization in a derived class.
The short answer is: you cannot define the primary template in the derived class, so you cannot declare a partial specialization in that class as well.
If it was possible , the following would have been possible too:
struct FooParent {
template <class>
struct Bar;
};
struct Foo: FooParent {
template <class T>
struct FooParent::Bar<T*> {};
};
Or this one if you prefer:
struct Foo: FooParent {
template <class T>
struct Bar<T*> {};
};
Unfortunately (?) they are not allowed and this would suffice to tell you that your attempt to specialize the class template is invalid as well.
Anyway, let's consider it a bit further.
The primary template is part of the member specification of Foo (see here for further details).
Thus, the question - where can I define such a template?, quickly becomes - where can I define any other member of the class?.
Again, the answer is - not in the scope of a derived class.
I'm pretty sure that a language-lawyer would give you more direct and straightforward explanation.
I'm also pretty sure that the same language-lawyer would curse me for having mentioned the wrong sections of the standard.
Anyway, I hope the few examples above can give you a base point from which to start.

Where to declare partial specializations of class member templates?

Here on stackoverflow I've found several comments (see for example the comment by jrok on this question) stating that partial specializations of class member templates are allowed at non-namespace scope (in contrast to explicit specializations) like in the example below:
class A {
template <class T, class U>
class B {};
template <class U>
class B<void, U> {};
};
Also, this example compiles just fine with both gcc and clang. However in the c++03 standard text I can only find 14.5.4 [temp.class.spec] §6 (or 14.5.5 §5 in c++11) about this issue:
A class template partial specialization may be declared or redeclared in any namespace scope in which its definition may be defined (14.5.1 and 14.5.2).
Along with the following example:
template<class T> struct A {
class C {
template<class T2> struct B { };
};
};
// partial specialization of A<T>::C::B<T2>
template<class T> template<class T2>
struct A<T>::C::B<T2*> { };
So, how about class template partial specializations at non-namespace scope? Are they allowed by the standard? And where can I find the relevant text?
Specifically, is my example valid (and would it still be valid if the enclosing class would be a template)? If not, are current compilers wrong to compile my example as stated above?
This seems to be a bit confusing, as I agree the paragraph you quoted seems to disallow partial specializations inside class definitions. However, there's [temp.class.spec.mfunc]/2:
If a member template of a class template is partially specialized, the
member template partial specializations are member templates of the
enclosing class template; [...] [Example:
template<class T> struct A {
template<class T2> struct B {}; // #1
template<class T2> struct B<T2*> {}; // #2
};
template<> template<class T2> struct A<short>::B {}; // #3
A<char>::B<int*> abcip; // uses #2
A<short>::B<int*> absip; // uses #3
A<char>::B<int> abci; // uses #1
— end example ]
IMHO this isn't very explicit; it doesn't allow partial specialization inside the class definition but rather (to me, seems to) specifies how member template specializations are treated.
Also see the Core Language Issue 708 and EWG Issue 41.

Explicit specialization of non-class, non-function members of a class template

Look at the code:
template <class x> struct Foo
{
int getX(x *p) { return(0); }
enum E12 { a };
};
template <> int Foo<int>::getX(int*)
{
return(-15);
}
template <> enum Foo<int>::E12
{
a, b, c
}
As it was discussed in Cannot overload function, the first specialization is legal and even works in MSVC. While the second specialization for enum does not even want to compile, saying "error C2988: unrecognizable template declaration/definition".
It seems to me that C++ is making relaitively unlogical exception for methods. Enum is just an example. The same thing can be applied to member classes, typedefs, etc.
I will be happy is some body will comment on this.
This is a very obscure new feature of C++11. File a bug report with Microsoft, although it is unlikely it will be given priority as almost nobody is aware this is allowed. The correct syntax would be
template <class x> struct Foo
{
int getX(x *p) { return(0); }
enum E12 { a };
};
template <> int Foo<int>::getX(int*)
{
return(-15);
}
template <> enum Foo<int>::E12
{
a, b, c
};
I've filed a bug with GCC. Can someone test on recent Clang?
In C++03, only classes and functions may be explicitly specialized. From the standard, C++03 14.7.3/1:
An explicit specialization of any of the following:
function template
class template
member function of a class template
static data member of a class template
member class of a class template
member class template of a class or class template
member function template of a class or class template
can be declared by a declaration introduced by template<>
A member enum is not such a case. (Generally speaking, an enum type is always defined only once at its first declaration.)
To obtain a templated enum or typedef, you can wrap it in a class template. In your case, it would be a member class template of Foo. Such a construct is called a metafunction.
C++11 also has alias templates, which are like templated typedefs, but they cannot be explicitly specialized.
The policy of only allowing classes and functions to be specialized, and then allowing such templates to encapsulate other things like enum and typedef, seems more consistent to me than allowing direct specialization of enum. But, perhaps the language is going in your preferred direction.