2011-04-22 88 views
10

我想定義模板函數,但不允許使用特定類型實例化。請注意,通常所有類型都是允許的,並且通用模板可以工作,我只想禁止使用一些特定的類型。禁止特定函數模板實例化

例如,在下面的代碼中,我希望阻止使用double與模板。這實際上並不妨礙實例化,但是由於沒有定義函數而導致鏈接器錯誤。

template<typename T> 
T convert(char const * in) 
{ return T(); } 

//this way creates a linker error 
template<> 
double convert<double>(char const * in); 

int main() 
{ 
    char const * str = "1234"; 

    int a = convert<int>(str); 
    double b = convert<double>(str); 
} 

該代碼只是一個演示,顯然轉換函數必須做更多的事情。

問題:在上面的代碼中,我怎麼能產生嘗試使用convert<double>實例化時,編譯器錯誤?


我能找到的最接近的相關問題是How to intentionally cause a compile-time error on template instantiation它涉及一個類而不是函數。

我需要這樣做的原因是因爲我希望阻止的類型實際上會編譯並使用通用版本進行操作。然而,這不應該是該功能合同的一部分,並且可能在所有平臺/編譯器和未來版本中都不支持。因此,我想阻止使用它。

+0

您已經這樣做了,是嗎? – Nawaz 2011-04-22 11:00:07

+0

不,這會導致關於缺少函數的鏈接器錯誤。這個錯誤不會告訴你問題在哪裏,它只會告訴你它在哪個模塊中。 – 2011-04-22 11:05:20

+3

你可以使用'static_assert'觸發一個編譯時錯誤:'template <> foo (const char *) {static_assert(false,「不允許」); }' – evnu 2011-04-22 11:10:38

回答

3

我會用你的函數調用中的靜態斷言函數實例化過程中創造適當的失敗:

template<typename T> 
class is_double{ static const int value = false; } 

template<> 
class is_double<double>{ static const int value = true; } 

template<typename T> 
T convert(const char *argument){ 
    BOOST_STATIC_ASSERT(!is_double<T>::value); 
    //rest of code 
} 

而且應該在一個函數內工作。

+0

應該是'static bool const value'。 :) – Xeo 2011-04-22 11:50:33

+0

@Xeo謝謝,修正。 – wheaties 2011-04-22 12:57:03

+0

啊是的。我覺得很愚蠢,因爲我在很多地方使用靜態斷言,不知何故它在這裏逃脫了我的想法。 – 2011-04-22 13:18:17

1

你可以使用一個仿函數,而不是一個功能:

template<typename T> 
struct convert { 
    T operator()(char const * in) const { return T(); } 
}; 
template<> struct convert<double>; 

int main() 
{ 
    char const * str = "1234"; 

    int a = convert<int>()(str); 
    double b = convert<double>()(str); // error in this line 

    return 0; 
} 

這將使你在實例化點錯誤。

通過添加輔助函數,你會得到想要的行爲:

template<typename T> 
struct convert_helper { 
    T operator()(char const * in) const { return T(); } 
}; 
template<> struct convert_helper<double>; 

template<typename T> 
T convert(char const * in) { return convert_helper<T>()(in); } 

int main() 
{ 
    char const * str = "1234"; 

    int a = convert<int>(str); 
    double b = convert<double>(str); 

    return 0; 
} 
+0

這也是一個不錯的選擇,因爲我基本上已經有其他原因的第二個方案。 – 2011-04-22 13:19:38

1

如果你不想靠static_assert或使代碼移植前的C++ 0x,使用此:

template<class T> 
void func(){ 
    typedef char ERROR_in_the_matrix[std::is_same<T,double>::value? -1 : 1]; 
} 

int main(){ 
    func<int>(); // no error 
    func<double>(); // error: negative subscript 
} 
+0

我不認爲'std:is_same'在C++ 11之前是可用的(或者是C++ 0x,因爲它在這裏) – Pharap 2014-12-15 00:16:59

0

考慮Boost disable_ifBoost TypeTraits

看看How can I write a function template for all types with a particular type trait?

這是一個例子:

#include <boost/type_traits.hpp> 
#include <boost/utility/enable_if.hpp> 

template<typename T> 
T convert(char const * in, 
      typename boost::disable_if<boost::is_floating_point<T>, T>::type* = 0) 
{ return T(); } 


int main() 
{ 
    char const * str = "1234"; 

    int a = convert<int>(str); 
    double b = convert<double>(str); 
    return 0; 
} 


這是該字符串的編譯錯誤

double b = convert<double>(str); 

1>。\ simple_no_stlport。't convert(const char *,boost :: disable_if,T> :: type *)'1>。\ simple_no_stlport.cpp(5)cpp(14):error C2770:無效顯式模板 參數):請參閱 「轉換」聲明