Reputation: 23941
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 int
s 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
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!");
}
};
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.
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 delete
d 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
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
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
Reputation: 121971
Declare the specialization but do not provide a definition will result in a failure:
template <>
void Careful::f(int value);
Upvotes: 2