How to define a non-instantiable template class? - c++

According to [temp.inst]:
Unless a class template specialization has been explicitly instantiated or explicitly specialized, 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.
So if I get it right, it is possible to define a template class and use it without odr-use it. It then will not be instantiated.
My question: what is the more short and/or idiomatic way to define a non instantiable template class?
(I shouln'd ask two questions in one thread, but when does "the completeness of the class type [would] affect the semantics of the program"?)

Related

template with lambda as unique default parameter on each instantiation

I'm looking for a way to automatically make default template parameter be unique each time a template is instantiated. Since unnamed function objects created by lambda expressions have different types I thought of adopting them somehow. With recent changes to standard daft removing "A lambda-expression shall not appear in ... a template-argument" restriction (see Wording for lambdas in unevaluated contexts) it seemed like a good idea. So I wrote the following kinda working snippet that compiles on recent gcc and clang:
#include <type_traits>
template<void ( * ) (void) = [](){}> class
unique final {};
static_assert(false == ::std::is_same_v<unique<>, unique<>>);
int main()
{
return 0;
}
Is this a viable approach or one of those "ill-formed, no diagnostic is required" cases?
Some additional context: I want to use this to implement Ada-style strong type definitions that should work in a single translation unit without manually inventing unique tags that would be otherwise unused:
struct _tag_WowInt {};
using Int = type<int, _tag_WowInt>;
struct _tag_SoUnique {};
using DifferentInt = type<int, _tag_SoUnique>;
Upd1: I would like to mention that approaches involving __COUNTER__ or similar macros won't work in general case because they will be expanded by preprocessor only once and won't yield unique types when used inside of template for example.
I believe that you are right, it seems to me that is "ill-formed, no diagnostic required". I think this is covered by
[temp.res/8.4] and [temp.res/8.5]:
(8.4) ― a hypothetical instantiation of a template immediately following its definition would be ill-formed due to
a construct that does not depend on a template parameter, or
(8.5) ― the interpretation of such a construct in the hypothetical instantiation is different from the interpretation
of the corresponding construct in any actual instantiation of the template. [Note: This can happen in situations including the following:
(8.5.1) ― a type used in a non-dependent name is incomplete at the point at which a template is defined but is complete at the point at which an instantiation is performed, or
(8.5.2) ― lookup for a name in the template definition found a using-declaration, but the lookup in the corresponding scope in the instantiation does not find any declarations because the using-declaration was a pack expansion and the corresponding pack is empty, or
(8.5.3) ― an instantiation uses a default argument or default template argument that had not been defined at the point at which the template was defined, or
(8.5.4) ― constant expression evaluation within the template instantiation uses
(8.5.4.1) ― the value of a const object of integral or unscoped enumeration type or
(8.5.4.2) ― the value of a constexpr object or
(8.5.4.3) ― the value of a reference or
(8.5.4.4) ― the definition of a constexpr function,
and that entity was not defined when the template was defined, or
(8.5.5) ― a class template specialization or variable template specialization that is specified by a non-dependent simple-template-id is used by the template, and either it is instantiated from a partial specialization that was not defined when the template was defined or it names an explicit specialization that was not declared when the template was defined.
— end note]
Even though your use case is not explicitly listed in the examples of the note, in my understanding the requirement implies that unique<> must refer to the same thing throughout the whole program, otherwise it is ill-formed, no diagnostic required.
This was CWG1850. The Committee appear to dislike this
kind of stateful meta-programming. The constexpr counter no longer works
in newer versions of the compilers.

How to create a template instantiation for an abstract baseclass?

I have an abstract class Primitive, which has some pure abstract functions.
Then i have a tree implementation with templates:
template<typename PrimitiveT>
class PrimitiveTree {
...
}
// explicit instantiation
template class PrimitiveTree<Project::Primitive>; // abstract
template class PrimitiveTree<SimpleTrianglePrimitive>; // implementation
which is used in another file as
PrimitiveTree<Primitive> *ptree;
With this code I get error C2259: 'Project::Primitive': cannot instantiate abstract class. When I remove the instantiation of the abstract class, I get linker errors that the corresponding symbol for PrimitiveTree<Primitive> is not found in the object file.
A similiar class with the methods inside the header file doesn't have these problems, when used with Primitive as template argument.
How do i need to instantiate the template class, such that the neccessary symbols are added to the object file, even when the template argument is an abstract class?
You need to ensure that the template PrimitiveTree<PrimitiveT> does not rely on PrimitiveT (the template parameter) being instantiable - in other words, not being abstract. One property of an abstract class is that it cannot be instantiated.
This means your PrimitiveTree template must only work with pointers or references to PrimitiveT, and never instantiate an actual instance PrimitiveT in any way. This means it is not possible to declare PrimitiveT as a data member (static or non-static). It is not possible to pass a PrimitiveT by value. It is also not possible dynamically create any instances with a new expression (e.g. some_pointer = new PrimitiveT[5]) since a new expression relies on the type being instantiable (i.e. not abstract).
Everywhere where PrimitiveT is used must be either a reference or a pointer. Defining or declaring a pointer or reference to PrimitiveT, or passing a reference/pointer as a function argument does not rely on PrimitiveT being instantiable.
If you write ANY code for PrimitiveTree that relies on PrimitiveT being instantiated, then the implementation cannot instantiate the template.
The "similar class" in another header file probably does not rely on Primitive being instantiable, since it follows guidelines like the above.

Implicit instantiation of specialization

I can't understand why the standard first defines template instantiation for templates as follows N3797::14.7/4 [temp.spec]:
The act of instantiating a function, a class, a member of a class
template or a member template is referred to as template
instantiation.
But further everywhere it uses the instatiation of the specialization, like the following N3797::14.7/4 [temp.spec]:
An instantiated template specialization can be either implicitly
instantiated (14.7.1) for a given argument list or be explicitly
instantiated (14.7.2).
I don't understand that. A template itself is a different concept than the template specilization, which could be an explicit specialization or a partial specialization. For instance N3797::14.5.5/1 [temp.class.spec]:
The primary template shall be declared before any specializations of
that template.
My question is about why the Standard first declare the instatiation concept for templates, but further it applies that concept for template specializations?
Moreover N3797::14.7/4 [temp.spec] defines the specialization concept as follows:
A specialization is a class, function, or class member that is either
instantiated or explicitly specialized (14.7.3).
So, the partial specialization is not a specialization, is it? I'm totally confused by those concepts. Couldn't you clarify it a bit?
This is a similar question here.
And now,I try to answer this question again.
A template is a type of infinite, so we can not instantiate a template, we can only be instantiated template specialization.
Implicitly instantiated, the current compilation unit requires the use of the template code, the compiler automatically instantiated template specialization.
Explicitly instantiated, we manually enter the code causes the compiler to instantiate a template specialization.
explicit specialization, given all the template parameters, and gives a non-generic code. Once the template type match, then instantiate this specialization.
Partial specialization, some parameters are given template and gives a non-generic code. Once the template type match, then instantiate this specialization.

Class template can be instantiated without members?

The Wikipedia article says this:
instantiating a class template does not cause its member definitions to be instantiated.
I can't imagine any class in C++ being instantiated, whether from a template or not, where that classes members were not also instantiated?
Many early C++ compilers instantiated all member functions, whether you ever called them or not.
Consider, for example, std::list, which has a sort member function. With a current, properly functioning compiler, you can instantiate list over a type that doesn't support comparison. If you try to use list::sort, it will fail, because you don't support comparison. As long as you don't call sort for that list, it's all fine though, because list<T>::sort won't be instantiated unless you call it.
With those older, poorly functioning compilers, however, trying to create list<T> meant that list<T>::sort was instantiated even though you never used it. The existence of list::sort meant that you needed to implement < for T, just to create a list<T>, even if you never actually used sort on a list of that type at all.
The standard clearly says that (both non-template and template) member methods instantiation should happen only when used.
An excerpt from C++ standard (N3690 - 14.7.1(2) Implicit instantiation)
2 Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.
Methods of a class are also members. Class Template methods are instantiated when they are called for that instantiated class. So it is possible that those member methods are never instantiated.

gcc problem with explicit template instantiation?

It is my understanding that either a declaration or typedef of a specialization ought to cause a template class to be instantiated, but this does not appear to be happening with gcc. E.g. I have a template class, template class Foo {};
I write
class Foo<double>;
or
typedef Foo<double> DoubleFoo;
but after compilation the symbol table of the resulting object file does not contain the members of Foo.
If I create an instance:
Foo<double> aFoo;
then of course the symbols are all generated.
Has anyone else experienced this and/or have an explanation?
The syntax for explicit instantiation is
template class Foo<double>;
See C++03 §14.7.2.
Hoping the functions get generated and linked, but not stripped after creating, but not using, an instance (the most minimal implicit instantiation), is quite a gamble.
You are talking about implicit instantiation. But that does only happen if the completenes of the class type would affect semantics of the program.
In your case, the class type doesn't need to be complete because the type you typedef can stay incomplete (class body is not needed, so there is no need to instantiate it). To illustrate, you can also say typedef class MyFunnyThing type; in a statement of its own, without ever defining that class anywhere.
If you create an object, the type of it has to be complete, and so the class template then is implicitly instantiated. Please note that implicit instantiation of a class template will not implicitly instantiate the member function or static datamember definitions, unless they are explicitly used elsewhere.
Also, to declare a specialization of a class-template, the whole point is to prevent an instantiation to happen, to tell the compiler "don't instantiate, because later i specialize it explicitly". The declaration if your specialization also misses a template<> in front of it.