Ignoring duplicate explicit instantiations of template classes in C++

extern template
c++ template function specialization
c++ template class
c++ template function in class
template specialization
c template return type
why templates are defined in header files
in instantiation of function template specialization

If I have a class:

template <typename T>
class MyClass
{ 
 // ...
};

and I explicitly instantiate it:

template class MyClass<int>;
template class MyClass<int>; // second time

I get an error on some compilers (Clang for example, but not on VC++ 2010). Why would I want to do this? Well, in some cases T may be a typedef to another type.

template class MyClass<my_type_1>;
template class MyClass<my_type_2>;

With certain build options, my_type_1 is the same as my_type_2 and in other cases it is different. How would I make sure that the above compiles in all scenarios? Is there a way to ignore the duplicate instantiation?

You could find another way to explicitly instantiate the template in a way that you can do metaprogramming on it.

Then instead of doing one instantiation per line, do them all in a pack. Run an n^2 algorithm on them (at compile time) to eliminate duplicates (or, honestly, you could probably skip that: depending on how you instantiate the template, it might not care).

Something like this, assuming Instantiate< Template, types< blah, foo, bar > > actually instantiates the list on the template passed in as the first argument:

#include <utility>
#include <type_traits>

template<typename T>
struct Test {};

template<typename... Ts>
struct types {};

template<template<typename>class Template, typename Types>
struct Instantiate {};

template<template<typename>class Template, typename T0, typename... Ts>
struct Instantiate<Template, types<T0, Ts...>>:
  Instantiate<Template, types<Ts...>>
{
  Template<T0>& unused();
};

template<typename U, typename Types>
struct prepend;

template<typename U, template<typename...>class pack, typename... Ts>
struct prepend< U, pack<Ts...> > {
  typedef pack<U, Ts...> types;
};
template<typename U, typename Types>
using Prepend = typename prepend<U, Types>::types;

template<typename U, typename Types, typename=void>
struct remove_type_from_types;
template<typename U, template<typename...>class pack>
struct remove_type_from_types<U, pack<>, void>
{
  typedef pack<> types;
};

template<typename U, template<typename...>class pack, typename T0, typename... Ts>
struct remove_type_from_types< U, pack<T0, Ts...>,
  typename std::enable_if< std::is_same<U, T0>::value >::type
>: remove_type_from_types< U, pack<Ts...> >
{};

template<typename U, template<typename...>class pack, typename T0, typename... Ts>
struct remove_type_from_types< U, pack<T0, Ts...>,
  typename std::enable_if< !std::is_same<U, T0>::value >::type
>
{
  typedef Prepend< T0, typename remove_type_from_types< U, pack<Ts...> >::types > types;
};

template<typename Types>
struct remove_duplicates {
  typedef Types types;
};

template<template<typename...>class pack, typename T0, typename... Ts>
struct remove_duplicates<pack<T0, Ts...>> {
private:
  typedef typename remove_type_from_types< T0, pack<Ts...> >::types filtered_tail;
  typedef typename remove_duplicates< filtered_tail >::types unique_tail;
public:
  typedef Prepend< T0, unique_tail > types;
};
template<typename Types>
using RemoveDuplicates = typename remove_duplicates<Types>::types;

static Instantiate<Test, RemoveDuplicates<types<int, double>> > unused;

int main() {

}

As noted, you can probably do away with the entire eliminate-duplicates bit, because of how I'm instantiating the use of the template. I am also not sure if the above use of each template is sufficient to instantiate it (ie, that it won't be optimized away somehow, and that the symbol will be exported).

(Recursion depth is n in the number of types, and total work done is n^2 in the number of types: that is shallow enough and fast enough for any reasonable number of types, I suspect. Fancier unique type removal is difficult, due to lack of weak ordering on naked types...)

duplicate explicit template instantiations disallowed?, I am trying to use explicit instantiations with my build scripts to achieve the template class A<X>; in A.cpp before linking A, B, and C together. However, explicit instantiation also has a few advantages because the instantiation can be tuned to the needs of the program. Clearly, the overhead of large headers is avoided. The source code of template definition can be kept hidden, but then no additional instantiations can be created by a client program.

Don't specialize for the typedefs, instead specialize for the relevant underlying types (such as int). That way you can typedef as many/few times as you like and you still always get the specializations you want.

Explicit template instantiation · Issue #3741 · RobotLocomotion , Furthermore, to explicitly instantiate a templated class required including two header files (in the appropriate order). A bit fragile. We can have the  The above example indeed does compile but it does not contain the given template instance. However, we can add specialized template support through explicit template instantiation which will add the symbols needed to link (properly) against the library for use.

You can define a preprocessor flag for you configuration and then put template inside an #ifdef block.

Function template - cppreference.com, class template argument deduction(C++17) 4) Explicit instantiation declaration with template argument deduction for all parameters it is implicitly instantiated for inlining, but its out-of-line copy is not generated in this TU) with default arguments, for which there is no explicit call argument, are ignored:. Ignoring duplicate explicit instantiations of template classes in C++. Is there a way to ignore the duplicate instantiation? C++ template explicit

Yakk saved my days. Actually I have lots of non-type template functions with parameters calculated at compile time depend on some "#define"s. I won't know in advance their values and I want to instantiate them explicitly. But when they are conflicting, the compiler stops with the error "duplicate ...". So I followed the idea of Yakk and I made a very simple version of his. I post it here for someones possibly interested.

File 1: instantiate.h

#ifndef INC_INSTANTIATE_H
#define INC_INSTANTIATE_H

#include <iostream>
#include <utility>
#include <type_traits>

using namespace std;

template<unsigned short base> void func();

template<unsigned short base>
struct test {
    test() {
        cout << "Class " << base << " instantiated.\n";
        func<base>();
    }
    void instantiate_me(){};
};

template<typename... Ts>
struct instances {};

template<typename Types>
struct Instantiate {};

template<typename T0, typename... Ts>
struct Instantiate<instances<T0, Ts...>> : Instantiate<instances<Ts...>>
{
    T0 unused;
};

#endif

File 2: instantiate.cpp

#include <iostream>
#include "instantiate.h"

using namespace std;

static Instantiate<instances<test<1>, test<2>, test<3>, test<4>>> unused;

template<unsigned short base>
void func() {
    cout << "Function " << base << " instantiated.\n";
}

static int initialize() {
    unused.unused.instantiate_me();
    return 0;
}

static int dummy = initialize();

File 3: main.cpp

#include <iostream>
#include "instantiate.h"
using namespace std;

int main() {
    cout << "Good day commander!\n";
}

It works perfectly with g++ 8.0.1 ubuntu 18.04 hyper-v windows 10. Here I do not need to care about template duplication because I explicitly use implicit instantiation, in one file there won't never be duplication. With all functions' definitions in one file, I can instantiate it in the constructor of the class "test" in the file instantiate.h. With plural files, I use one Instantiate, one initialize and one dummy for each, with possibly plural implementations of the class "test".

C++ Template Instantiation Issues, lib_char_stack.push('c'); char_val = lib_char_stack.pop();. } So which, if any, of those stack template functions were instantiated? Also ignore the ___sti symbols. And, it avoids the problem of duplicate entities that would arise The explicit instantiation line must refer to the actual template, and not the  Duplicate instances of a template can be avoided by defining an explicit instantiation in one object file, and preventing the compiler from doing implicit instantiations in any other object files by using an explicit instantiation declaration, using the extern template syntax: extern template int max (int, int);

using the extern template syntax can solve the problem, example:

 extern template int max (int, int);

Proposals:Explicit Instantiation - KitwarePublic, itkFoo.h namespace itk { template <class T> class Foo { public: void MethodA(); }; } The explicit template instantiation syntax tells the compiler to instantiate a copy of every symbol in the template. Now when The C preprocessor does not understand C++ template arguments, and will treat this as a call to  Explicit specialization may be declared in any scope where its primary template may be defined (which may be different from the scope where the primary template is defined; such as with out-of-class specialization of a member template) . Explicit specialization has to appear after the non-specialized template declaration.

Template argument deduction, class template argument deduction(C++17) In order to instantiate a function template, every template argument must if any template argument remains neither deduced nor explicitly specified, compilation fails. c) otherwise, if A is a cv-qualified type, the top-level cv-qualifiers are ignored for deduction:. The duplicate instances will be discarded by the linker, but in a large program, this can lead to an unacceptable amount of code duplication in object files or shared libraries.Duplicate instances of a template can be avoided by defining an explicit instantiation in one object file, and preventing the compiler from doing implicit instantiations

Function template, extern template return-type name ( parameter-list ) ;, (4), (since C++11) Explicit instantiation of a function template or of a member function of a class it is implicitly instantiated for inlining, but its out-of-line copy is not generated in this TU) with default arguments, for which there is no explicit call argument, are ignored:. Any missing template instantiations can be determined at link time, however, and added to the list of explicit instantiations, by noting which functions are undefined. Explicit instantiation can also be used to make libraries of precompiled template functions, by creating an object file containing all the required instantiations of a template function (as in the file 'templates.cc' above).

C++11 Language Extensions – Templates, C++ FAQ, A template specialization can be explicitly declared as a way to suppress #​include "MyVector.h"; extern template class MyVector<int>; // Suppresses implicit instantiation a format specifier (ignore which one it is); std::cout << value; // use first Given that definition, we can make tuples (and copy and manipulate them):​. Instead, a reference to that specialization that would otherwise cause an implicit instantiation can refer to an explicit instantiation definition in the same or another TU. foo.h. #ifndef FOO_H #define FOO_H template <class T> void foo(T x) { // complicated implementation } #endif foo.cpp

Comments
  • Personally I keep template code in headers and let the compiler instantiate it automatically as needed. I guess in some situations that would balloon the compile time though.
  • Very interesting. I also not sure whether the template use in the Instantiate struct enough for an explicit instantiation. I don't have access to a C++11 compiler so I cannot test this, but will definitely save it for later study. Quite a clever approach!
  • @samaursa if the template use is not enough, do a daisy chain call. Then call the bottom one in an exported function that is not called by anyone. The templates will be instantiated in order to export that function, and later at linking the exported function will be eliminated, but the templates may not if used elsewhere...
  • I tried using C++11, and apparently doesn't work. Reference in Instantiate apparently doesn't perform an explicit instantiation. Good idea though. I'm also looking for a solution to this, using macros is very boring and not quite efficient for my use.
  • @brahmin As another idea, do a sum-of-sizeof. sizeof basically requires instantiation.
  • @Yakk doesn't change anything for me. I don't think you can explicitly instantiate except from using template : class Test<int>. And it apparently needs to be done in a cpp file, out of any function. I'm afraid there's no solution to this problem..
  • Not a bad suggestion but defeats the purpose of the typedef. If the type changes, I will get linking errors which will take me at least a few minutes to figure out. Better than what I have right now though (+1).
  • That is a lot of defines! And sometimes the types are not defined by a configuration but can change along the way. For example, recently, a certain TextureCoord type that another class was using was a typedef of a Vec2f but was changed to Vec3f (already instantiated) causing compile errors on XCode.