2013-08-07 110 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把函數斷言。 –