2013-08-07 63 views
3

我有一个泛型类,带有一个函数,我只想在编译时限制为浮点类型的实例。如下例所示:访问函数的限制

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

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

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

我一直在寻找SFINAE,但我根本无法得到它的工作,所以经过几个小时的失败,我要求你的帮助。

谢谢:)

+1

你试过了什么?你可以用['std :: is_floating_point'](http://en.cppreference.com/w/cpp/types/is_floating_point)和['std :: enable_if'](http:// en。 cppreference.com/w/cpp/types/enable_if)。 – juanchopanza

+0

目前我正在包装功能在另一个功能,如下所示: 'void some_other_method(){some_method(std :: is_floating_point ()); }' 'void some_method(){}' 这有效,但我想要一个解决方案,我不必包装功能。 – Jesper

+0

@juanchopanza尽管你使'some_method'成为模板,你可以使你的例子工作。我正在寻找一个解释此处危险机制的先前答案。 –

回答

6

您可以使用std::is_floating_pointstd::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 
} 
+0

@PetrBudnik是第一个,但这个答案更加详细,因此被接受。干杯! – Jesper

6

使用static_assert,如果你的编译器支持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 
} 

然后会有编译错误,如果你尝试调用非浮点参数此方法。

而对于没有浮点:

static_assert(!std::is_floating_point<T>::value, "and only for non-floating point"); 
+1

你需要否定条件。 – jrok

+0

@jrok:谢谢,我编辑了我的答案。 – user1837009

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; 
*/ 
} 
+0

不完全一样。注意“如何让编译器拒绝some_method用于非浮点类型的ClassName?”。 –

+0

@Mgetz是的,有一个解决方案(见其他答案)。你可以得到相同的结果,即所提出的“静态if”可以在没有它的情况下实现。你可以引用我的话。 –

+0

@Mgetz不,它没有。除非使用函数定义,否则不会实例化。请参阅http://coliru.stacked-crooked.com/view?id=46f36b442ad191ec5bb171388773d46d-6bd941bd569898d6f94f2545382ce976,http://coliru.stacked-crooked.com/view?id=bb47a5533c53dc8a49441d51bcfaef8c-6bd941bd569898d6f94f2545382ce976,http://coliru.stacked-crooked .com/view?id = a520465ed8ca7d7c84237dd3450542ec-6bd941bd569898d6f94f2545382ce976和http://coliru.stacked-crooked.com/view?id=8482aeca87df479ac97193bf36b7dbd4-6bd941bd569898d6f94f2545382ce976作为示例。 –

3

事情是这样的:

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

编辑来阐述。这将导致以下结果。编译器将仅为具有浮点模板参数的ClassName生成some_method()。它不会为非浮点类型生成,并会导致编译时错误。

#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); 
} 
+0

请问这个模板中的T == T类模板中? – Jesper

+0

@Jesper使它成为默认类型。我给出了一般想法。请参阅编辑。 – lapk

1

As detailed in this answer,你需要的成员函数是SFINAE工作模板(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 
    } 
}; 
0

更新每R. Martinho费尔南德斯评论

#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; 
} 
+0

如果你要断言相反的使能条件,SFINAE是什么? –

+0

当SFINAE选择应该禁止的* non * -floating-point-T变体时,我断言R(= T)*是*浮点。所以它吧。 –

+1

当然,但它也barf,如果你只是没有任何SFINAE把函数断言。 –