问题
I have a generic class with a function that I want to restrict to instances of floating point types only, at compile time. As shown in the example below:
template <typename T>
class ClassName
{
// instance variables, etc..
void some_method()
{
// do stuff, but only for floating point types
}
}
How do I make the compiler reject the usage of some_method for ClassName of non-floating point types?
I have been looking at SFINAE but I simply can't get it to work, so after several hours of failing I'm asking for your help.
Thanks :)
回答1:
You can use a combination of std::is_floating_point
and std::enable_if
to only enable the function for floating point types:
#include <type_traits>
template <typename T>
class ClassName
{
// instance variables, etc..
public:
template<typename T2 = T,
typename = typename std::enable_if< std::is_floating_point<T2>::value >::type>
void some_method()
{
// do stuff, but only for floating point types
}
};
int main()
{
ClassName<double> d; // OK
d.some_method(); // OK
ClassName<int> i; // OK
i.some_method(); // ERROR
}
回答2:
Use static_assert, if your compiler support c++11
void some_method()
{
static_assert( std::is_floating_point<T>::value, "Only for floating points" );
// do stuff, but only for floating point types
}
Then there will be compiler error if you try call this method for non floating points parameter.
And for not-floating point:
static_assert( !std::is_floating_point<T>::value, "and only for non-floating point" );
回答3:
Something like this:
template< typename Tdummy = T, typename = typename std::enable_if< std::is_floating_point< Tdummy >::value >::type >
void some_method()
{
}
EDIT to elaborate. This will result in the following. Compiler will generate some_method()
only for ClassName
with floating-point template parameter. It will not be generated for non-floating types and will result in a compile-time error.
#include <type_traits>
template <typename T>
class ClassName
{
// instance variables, etc..
template< typename Tdummy = T, typename = typename std::enable_if< std::is_floating_point< Tdummy >::value >::type >
void some_method()
{
// do stuff, but only for floating point types
}
void some_general_method
{
// general stuff for all types
}
};
int main()
{
ClassName< float > bar;
ClassName< int > foo;
bar.some_general_method(); // OK
foo.some_general_method(); // OK
bar.some_method(); // OK
foo.some_method(); // Compile-time ERROR
return( 0 );
}
回答4:
void some_method(){
if (std::is_floating_point<T>::value)
{
// do stuff, but only for floating point types
}
else
{
return;
}
}
I tried with boost::is_floating_point
too :-
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_floating_point.hpp>
template <typename T>
class ClassName {
typename boost::enable_if<boost::is_floating_point<T> >::type
some_method(const T & t)
{
}
};
int main()
{
ClassName<float> p; //Compiles
/* Following throws error,
error: no type named 'type' in
'struct boost::enable_if<boost::is_floating_point<int>, void>'
ClassName<int> q;
*/
}
回答5:
As detailed in this answer, you need the member function to be a template for SFINAE to work (Live example at Coliru):
template <typename T>
class ClassName
{
// instance variables, etc..
public:
template <typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
void some_method()
{
// do stuff, but only for floating point types
}
};
回答6:
Update per R. Martinho Fernandes comment
#include <type_traits>
template <typename T>
struct ClassName
{
// instance variables, etc..
template<typename R = T>
void some_method()
{
static_assert(std::is_floating_point<R>::value,
"ClassName<T>::some_method is implemented only for floating "
"point T");
// do stuff, but only for floating point types
}
};
int main()
{
ClassName<float> f;
f.some_method();
ClassName<int> i;
i.some_method(); // <-- static_asserts here
return 0;
}
来源:https://stackoverflow.com/questions/18108600/restriction-of-access-to-function