7

Other than the preprocessor, how can I conditionally enable/disable explicit template instantiations?

Consider:

template <typename T> struct TheTemplate{ /* blah */ };

template struct TheTemplate<Type1>;
template struct TheTemplate<Type2>;
template struct TheTemplate<Type3>;
template struct TheTemplate<Type4>;

Under some compilation conditions, Type3 is the same as Type1 and Type4 is the same as Type2. When this happens, I get an error. I'd like to detect that the types are the same and not instantiate on Type3 and Type4 as in

// this does not work
template struct TheTemplate<Type1>;
template struct TheTemplate<Type2>;
template struct TheTemplate<enable_if<!is_same<Type1, Type3>::value, Type3>::type>;
template struct TheTemplate<enable_if<!is_same<Type2, Type4>::value, Type4>::type>;

I've diverted myself trying enable_if and SFINAE (and I believe I know why they fail), but only the preprocessor has worked (ugh). I'm thinking about putting the types in a tuple or variadic, removing duplicates, and then use the remainder for instantiation.

Is there a way to conditionally enable/disable explicit template instantiation based on template argument types?

walrii
  • 3,472
  • 2
  • 28
  • 47
  • Is this a duplicate? http://stackoverflow.com/questions/11982012/how-can-i-provide-template-specializations-for-typedefs-of-the-same-type – jogojapan Dec 18 '12 at 03:22
  • Does explicitly instantiating one class imply implicit instantiation of all base types? – Ben Voigt Dec 18 '12 at 03:29
  • 1
    @jogojapan - No, this explicit *instantiation* which is different from *specialization*. – walrii Dec 18 '12 at 03:30
  • In fact, why is repeated explicit instantiation an error? – Ben Voigt Dec 18 '12 at 03:31
  • @BenVoigt - I don't know if it should, but gcc 4.6.3 reports `error: duplicate explicit instantiation of ‘struct TheTemplate’ [-fpermissive]` – walrii Dec 18 '12 at 03:34
  • BTW, looks like inheritance doesn't help here: "An explicit instantiation that names a class template specialization is also an explicit instantiation of the same kind (declaration or definition) of each of its members **(not including members inherited from base classes)** that has not been previously explicitly specialized"... – Ben Voigt Dec 18 '12 at 03:42
  • 1
    @BenVoigt it's an error for the same reason as multiple definitions of a function are an error: ODR violation. An explicit instantiation is not a template (with weak linkage), it's a class, so must only be defined once. – Jonathan Wakely Dec 18 '12 at 10:33

1 Answers1

7
template <typename T> struct TheTemplate{ /* blah */ };

template<int> struct dummy { };

template struct TheTemplate<Type1>;
template struct TheTemplate<Type2>;
template struct TheTemplate<conditional<is_same<Type1, Type3>::value, dummy<3>, Type3>::type>;
template struct TheTemplate<conditional<is_same<Type2, Type4>::value, dummy<4>, Type4>::type>;

This still produces four explicit instantiations, but they won't be duplicates in the case where Type3 is the same as Type1 (unless Type1 is dummy<3>!)

Kirill Kobelev
  • 10,252
  • 6
  • 30
  • 51
Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • The downside is that `dummy` must meet the requirements of `TheTemplate` or the instantiation will give an error, so `dummy` might need to have members added to it, or you could write a partial specialization of `TheTemplate>` – Jonathan Wakely Dec 18 '12 at 20:44
  • 2
    Alternatively, you can switch on the template that you instantiate: `template struct conditional::value, details::TheTemplate<3>, TheTemplate>::type::TheTemplate;`. By calling the `dummy` template `TheTemplate` too, the injected class name of one of its specializations is called `TheTemplate`, so that you in both cases can access `::type::TheTemplate` and instantiate whatever class type that is. Similar to http://stackoverflow.com/a/13332744/34509 – Johannes Schaub - litb Dec 18 '12 at 22:55
  • @Johannes Nice, I didn't think of that – Jonathan Wakely Dec 19 '12 at 16:11
  • What is details:: in the example? – gerardw Mar 21 '14 at 13:46
  • @gerardw, I think Johannes is suggesting replacing the `dummy` class template in my answer with `namespace details { template struct TheTemplate { }; }` which is a different class template but with the same name – Jonathan Wakely Mar 21 '14 at 15:30