This issue has been discussed a few times but all the solutions I have found either didn't work or were based on boost's static assert. My problem is simple. I have a class, and I only want to allow real types (double and float). I want a compile-time error if I try to instantiate the class with a type other than float or double. I am using Visual C++ 11. Here is what I have tried:
template <typename RealType>
class A
{
// Warning C4346
static_assert(std::is_same<RealType, double>::value || std::is_same<RealType, float>::value);
}
template <typename RealType>
class A
{
// Error C2062: type 'unknown' unexpected
static_assert(decltype(RealType) == double || decltype(RealType) == float);
}
Any ideas? Thanks in advance!
One solution I've seen is to use std::enable_if
in a type alias. Something like:
using value_type = typename std::enable_if<
std::is_same<float, RealType>::value ||
std::is_same<double, RealType>::value,
RealType
>::type;
value_type
only exists if RealType
is exactly float
or double
. Otherwise, the type is undefined and compilation fails.
I'd warn about being too strict with types, though. Templates are as powerful as they are partly because the duck typing they do means that any type that can be used the way you want to use it, will work. Disallowing types for the sake of disallowing types generally doesn't gain you much, and can make things less flexible than they could be. For example, you wouldn't be able to use a type with more precision, like a big-decimal type.
In your first example, static_assert
should take a second parameter which would be a string literal, otherwise it's deemed to fail (edit: dropping the the second parameter is legal since C++17). And this second argument cannot be defaulted.
Your second example is incorrect for several reasons:
decltype
is meant to be used on an expression, not on a type.- You simply cannot compare types with
==
, the correct way to do this is what you try in your first attempt withstd::is_same
.
So, the right way to do what you are trying to achieve is:
#include <type_traits>
template <typename RealType>
class A
{
static_assert(std::is_same<RealType, double>::value || std::is_same<RealType, float>::value,
"some meaningful error message");
};
Moreover, I bet you are trying to constrict your template to floating points values. In order to do this, you can use the trait std::is_floating_point
:
#include <type_traits>
template <typename RealType>
class A
{
static_assert(std::is_floating_point<RealType>::value,
"class A can only be instantiated with floating point types");
};
And as a bonus, take this online example.
This way it also allows specialization for various types:
template<typename T, typename Enable = void>
class A {
/// Maybe no code here or static_assert(false, "nice message");
};
/// This specialization is only enabled for double or float.
template<typename T>
class A<T, typename enable_if<is_same<T, double>::value || is_same<T, float>::value>::type> {
};
来源:https://stackoverflow.com/questions/16976720/how-do-i-restrict-a-template-class-to-certain-built-in-types