Reputation: 41
I want to inhibit certain types from template instantiation. I want to implement an algorithm in a library which works only for real numbers, and not for complex or integer types. So user instantiations with float/double/long double/mpf_class should be ok, but i.e. complex<float>
must not occur.
Specializations would produce code bloat with code that will never be used. (I could generate ctors only throwing exceptions).
template<typename T>
void work (T & result, T const & input) { /* work for any real type */ }
Ideally there should be a compiler message saying "this ... instantiation is not allowed".
Explicit lists of allowed templates would be too restrictive.
Upvotes: 2
Views: 78
Reputation: 51840
You can use static_assert
to generate the exact compile-time error message you want:
#include <type_traits>
template<typename T>
void work (T & result, T const & input)
{
static_assert(std::is_floating_point<T>::value, "Only floating point types are allowed.");
// ...
}
If you're using C++17, you can write it a bit shorter:
static_assert(std::is_floating_point_v<T>, "Only floating point types are allowed.");
Upvotes: 3
Reputation: 170084
For completeness sake, there's also SFINAE.
template<typename T>
auto work (T & result, T const & input) -> std::enable_if_t<std::is_floating_point_v<T>>
{
// ..
}
The void
is omitted because it's the default type enable_if_t
resolves to when the condition holds. It's just a stylistic choice.
The difference here is that the function won't even be considered to exist in overload resolution. So you can check if work
is callable with an argument in other SFINAE contexts. Putting the check in a the function template's signature is the only way to accomplish that.
Upvotes: 1
Reputation: 26800
You can just define that particular specialization of the template as delete
d, if you want to prevent instantiation for a particular type.
A minimal example preventing instantiation with T=int
:
template<typename T>
void work (T & result, T const & input) { (void)result; (void)input; }
template<>
void work (int & result, int const & input) = delete;
int main()
{
float f1 = 3.14;
float f2 = 1.414;
work(f1, f2); //works
int i1 = 1;
int i2 = 2;
work(i1, i2); //Doesn't work
}
The compiler will complain for the instantiation with int
.
error: use of deleted function 'void work(T&, const T&) [with T = int]'
16 | work(i1, i2); //Doesn't work
Upvotes: 2