How to Prevent Non-Specialized Template Instantiation

How to prevent non-specialized template instantiation?

Just don't define the class:

template <typename Type>
class Foo;

template <>
class Foo<int> { };

int main(int argc, char *argv[])
{
Foo<int> f; // Fine, Foo<int> exists
Foo<char> fc; // Error, incomplete type
return 0;
}

Why does this work? Simply because there isn't any generic template. Declared, yes, but not defined.

block non-specialized template c++

Sure: just don't define it and you'll get a linker error if you try to use it:

template <typename T>
void foo(); // not defined

template <>
void foo<int>() { }

Alternatively, you can use some variation of a static assert to give a "nicer" compile-time error. Here is an example using the C++0x static_assert. Note that you must make the false value dependent upon the template parameter, otherwise the static_assert may be triggered when the template is parsed.

template <typename T>
struct dependent_false { enum { value = false }; };

template <typename T>
void foo()
{
static_assert(dependent_false<T>::value, "Oops, you used the primary template");
}

Note that it's usually best not to specialize function templates. Instead, it is better to delegate to a specialized class template:

template <typename T>
struct foo_impl
{
static_assert(dependent_false<T>::value, "Oops, you used the primary template");
};

template<>
struct foo_impl<int>
{
static void foo() { }
};

template <typename T>
void foo()
{
return foo_impl<T>::foo();
}

Disable construction of non fully specialized template class

This seems to be a C++'s most vexing parse issue:

Container<int> a(Container<char>());

This is actually just a function declaration: It declares a function a that returns a Container<int> object and takes a pointer to a function that returns Container<char> and takes nothing.

Since it is just a function declaration, it does not instantiate Container<char> at all and, therefore you are not getting any error.

You could use brace syntax instead of parenthesis, i.e.:

Container<int> a{Container<char>()};
Container<int> b(Container<char>{});
Container<int> c{Container<char>{}};

The code above does declare three objects: a, b and c.


Getting a custom error when instantiating Container<>'s primary template

You could define the following template, deferred_false, as:

template<typename>
struct deferred_false {
static constexpr auto value = false;
};

or simply as:

#include <type_traits>
template<typename> struct deferred_false: std::false_type{};

Then, place a static_assert that uses this deferred_false<T>::value in the definition of your class template :

template<class T>
class Container final : public AbstractContainer
{
static_assert(deferred_false<T>::value, "Trying to instantiate Container<>");
};

This way, the assertion will fail at compile time when the primary template of Container is going to be instantiated, but won't fail when the primary template is not being instantiated, since the condition of the static_assert depends on the template parameter (i.e.: T).

That is, if there is no specialization of Container for Foo and you have:

Container<Foo> a;

You will get the following compile-time error:

error: static assertion failed: Trying to instantiate Container<>

Is it possible to prevent a C++ template being used without specialization?

You should be able to declare the function without actually defining it in the generic case. This will cause a reference to an unspecialized template to emit an Undefined Symbol linker error.

template<class T>
void foo();

template<>
void foo<int>() {
// do something here
}

This works just fine for me with clang++.

Prevent compilation of unused template specialization in c++

Why does the compiler need to generate code for every specializations?

The compiler doesn't need to generate code for unused template specialization, but it must ensure it's definition is correct according to the same rules as those applied to generic classes.

How to prevent the compiler to compile code for unused specialization?

You cannot. Unused specializations must compile, but if they do, the (decent) compiler won't produce binary code for it.

But, if you told us what you exactly expect, we might give you alternative. As example:

enum TYPE
{
TYPE_A,
TYPE_B
};

template<TYPE T>
struct MayBeNotDefined;

// FOR PROJECT WITH MayBeNotDefined ONLY ---
template<>
struct MayBeNotDefined<TYPE_B> { typedef char type; };
// FOR PROJECT WITH MayBeNotDefined ONLY ---

template<TYPE T>
struct Foo
{
typename MayBeNotDefined<T>::type* B;
};

template<>
struct Foo<TYPE_A>
{
int* A;
};

int main()
{
Foo<TYPE_A> a;
a.A = new int;

// FOR PROJECT WITH MayBeNotDefined ONLY ---
Foo<TYPE_B> b;
b.B = new char;
// FOR PROJECT WITH MayBeNotDefined ONLY ---
}

(this works even if you remove the two specified blocks)

How to prevent specialization of a C++ template?

An alias template can not be specialized and has the behaviour you need for class templates.

template<class T>
struct my_class_implementation_which_should_not_be_used_directly
{
// impl
};

template<class T>
using my_class = my_class_implementation_which_should_not_be_used_directly<T>;

In addition you should document that specialising my_class_implementation_which_should_not_be_used_directly results in undefined behavior. Now your libraries user can not specialize my_class accidentally and is warned about the class with the ugly name directly.

disable function template specialization or overload with constexpr variable

std::enable_if_t<false> is invalid (for any specialization).

To make it SFINAE friendly, you have to make the condition dependent:

constexpr bool SWITCH = false;

namespace glog {

template <bool b = SWITCH>
std::enable_if_t<b> MakeCheckOpValueString(std::ostream* os, const Duration& v) {
(*os) << v.count();
}
}

C++ non-specialized member in template class

I think there is one important piece of information missing: Are the non-specialized methods overriding virtual methods of the TBase class? This is the central issue here.

If not, then you can just create another class for the non-specialized methods, and inherit (publicly) from both classes in your CTemplateInherit class. Problem solved.

If, however, the non-specialized methods override virtual methods of the TBase class, then it is only slightly more complicated:

Solution 1) Take all the non-specialized functions and regroup them into one "detail" header. Either as a group of (non-template) free-functions (if it is easy enough to just pass input-outputs as parameters) or as a (non-template) class with the non-specialized data members it requires. Then, you define all those functions (implement them) inside a corresponding cpp file (which you will later compile into the DLL).

Then, in your CTemplateInherit class template, simply forward the non-specialized function calls to the set of "detail" functions. Because templates inline by default, the overhead will be nil. If you needed to regroup the "detail" functions into one class (non-template), then, simply use private inheritance, preventing function-name conflicts. Then, you can access the data members of the "detail" class like any other inherited data member, and you can forward the non-specialized function calls to the "detail" class implementation which you can compile into a DLL (if you have a suitable framework for exporting classes from a DLL (because plain C++ doesn't have a reliable mechanism for that), but your question seems to imply that you do).

The only issue with this solution is the annoying creation of several simple forwarding functions. But IMHO, that is a reasonable price to pay for tucking away an implementation in a DLL (almost any time you want to do that, you end up writing a bunch of wrapper functions).

Solution 2) If there is a set of non-specialized virtual functions from the base class, then that subset is certainly not dependent on the actual type of TBase (I mean, the prototypes of those functions can be formed without it). Then, it means that you can regroup that subset of functions into another base-class from which TBase is expected to be inheriting from. Let's call it TNonSpecialBase. At this point, you can set up the following hierarchy:

class TNonSpecialBase {
// set of pure-virtual functions that are not special.
};

// this is an example of a class that could act as a TBase:
class TExampleBase : public virtual TNonSpecialBase {
// set of virtual functions that are special to TExampleBase.
};

class CNonSpecialDerived : public virtual TNonSpecialBase {
// declaration of non-specialized functions that override the function in TNonSpecialBase.
};

template <typename TBase>
class CTemplateInherit : public TBase, public CNonSpecialDerived {
// set of virtual functions that are specialized for the template argument TBase.
};

With the above setup, the specialized functions must end up in the header file of CTemplateInherit, but the non-specialized functions, regrouped in CNonSpecialDerived can be defined in a separate cpp file (and compiled into a DLL). The magic trick here is the use of the virtual inheritance to allow for the final class to have a single virtual-table for the base class TNonSpecialBase. In other words, this allows the class CNonSpecialDerived to override the virtual functions in TBase which are inherited from TNonSpecialBase, as long as TBase does not override any of those functions (in which case, the compiler will call it ambiguous). This way the user can deal with a pointer to a TBase object, call any of its virtual functions, which will cause either a dispatch towards the CTemplateInherit implementations (specialized) or the CNonSpecialDerived implementations (presumably, in the DLL).



Related Topics



Leave a reply



Submit