3

我有一个泛型类,我想在编译时将其限制为仅浮点类型的实例。如下例所示:

template <typename T>
class ClassName
{
    // instance variables, etc..

    void some_method()
    {
        // do stuff, but only for floating point types
    }
}

如何让编译器拒绝对非浮点类型的 ClassName 使用 some_method?

我一直在研究 SFINAE,但我根本无法让它工作,所以在失败了几个小时后,我请求你的帮助。

谢谢 :)

4

6 回答 6

6

您可以使用std::is_floating_point和的组合std::enable_if来仅启用浮点类型的功能:

#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
}
于 2013-08-07T16:39:16.053 回答
6

如果您的编译器支持 c++11,请使用 static_assert

void some_method()
{
    static_assert( std::is_floating_point<T>::value, "Only for floating points" );
    // do stuff, but only for floating point types
}

如果您尝试为非浮点参数调用此方法,则会出现编译器错误。

对于非浮点数:

static_assert( !std::is_floating_point<T>::value, "and only for non-floating point" );
于 2013-08-07T16:26:58.503 回答
3

像这样的东西:

template< typename Tdummy = T, typename = typename std::enable_if< std::is_floating_point< Tdummy >::value >::type >
 void some_method()
{
}

编辑详细说明。这将导致以下结果。编译器只会生成带有浮点模板参数的some_method()for 。ClassName它不会为非浮动类型生成,并会导致编译时错误。

#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 );
}
于 2013-08-07T16:32:23.603 回答
2
void some_method(){

    if (std::is_floating_point<T>::value)
    {
        // do stuff, but only for floating point types
    }
    else
    {
        return;
    }
}

我也试过boost::is_floating_point:-

#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;
*/
}
于 2013-08-07T16:27:07.737 回答
1

如本答案中所述,您需要将成员函数作为 SFINAE 工作的模板(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
    }
};
于 2013-08-07T16:44:33.423 回答
0

根据 R. Martinho Fernandes 的评论更新

#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;
}
于 2013-08-07T16:48:50.920 回答