Tamás Szelei
Tamás Szelei

Reputation: 23941

Fail compilation if a certain specialization is used

Is it possible to specialize a template in such a way that results in a compilation error when that specialization is instantiated? For example, I have a class for which ints don't make sense as a type:

class Careful
{
    template <typename T>
    void f(T value) { std::cout << "Non-specialized version"; }
};

template <>
void Careful::f(double value)
{
    std::cout << "specialization for double";
}

template <>
void Careful::f(int value)
{
    // make this one fail to compile
}

Is this possible somehow (ideally with a meaningful error message)?

Upvotes: 3

Views: 309

Answers (4)

Ken Wayne VanderLinde
Ken Wayne VanderLinde

Reputation: 19349

If you want customized error messages, and can use C++11, you can go for the new static_assert:

class Careful
{    
    template <typename T>
    void f(T value) {
        static_assert(std::is_same<T, int>::value, "Don't call f with an int!");
    }
};

EDIT

I thought I might explain one thing. Sure, it's possible to cause an error message for a given specialization, either by static_assert, enable_if or by not defining the function (these are the three answers which have been given). But I don't know of a way to force an error for a given specialization.

The static_assert and enable_if techniques are subject to SFINAE, so you won't get an error if someone later adds this function to the Careful class:

void f(int value)
{
    std::cout << "Overloaded!" << std::endl;
}

(I think that's a good thing, but it's still worth noting). Similarly, the code template<> void Careful::f(int value); is just a forward declaration for this specialization of f - later, someone could add a definition for it.

Edit 2

Yeah this question looks answered, but I thought I should follow up with the most direct approach (and IMO, the "correct" approach): use delete.

class Careful
{
    template <typename T>
    void f(T value) { std::cout << "Non-specialized version"; }
};

template <>
void Careful::f(double value)
{
    std::cout << "specialization for double";
}

template <>
void Careful::f(int value) = delete;

delete works kind of like @hmjd's approach of not defining the function, but it explicitly says that no one can provide an implementation of the function. Also, the compiler message will be descriptive (note that it's a compiler error, not a linker error, so it's probably easier to find the source of the error). On g++, the error message for using the deleted function reads error: use of deleted function ‘void Careful::f(T) [with T = int]’. And if someone later tries to define the function elsewhere, they'll end up getter the error redefinition of ‘void Careful::f(T) [with T = int]’ as opposed to no error at all.

Upvotes: 4

J&#246;rg Beyer
J&#246;rg Beyer

Reputation: 3671

You can at least make linking fail. Just don't implement the function for the type(s), that makes no sense:

#include <iostream>
using namespace std;

class Careful
{
public:
    template <typename T>
    void f(T value) { std::cout << "Non-specialized version"; }
};

template <>
void Careful::f(double value)
{
    std::cout << "specialization for double";
}

template <>
void Careful::f(int value); // int makes no sense. As long as you don't implement it for this type, compilation will fail at instantiation.

int main() {
    Careful x;
    x.f(3.14);
    x.f(42); // this will fail
}

with my g++, I get this error in the linking step:

 main.cpp:(.text+0x4b): undefined reference to `void Careful::f<int>(int)'

This is not a customized message, but the linking fails.

Upvotes: 1

Adrien
Adrien

Reputation: 146

You can use boost::enable_if to produce a compile time error when a template is specialized for a specific type

Upvotes: 3

hmjd
hmjd

Reputation: 121971

Declare the specialization but do not provide a definition will result in a failure:

template <>
void Careful::f(int value);

Upvotes: 2

Related Questions