2012-01-13 51 views
11

我試圖讓我的模板函數產生一個編譯時錯誤,如果非專業基礎版本實例化。我嘗試了通常的編譯時斷言模式(負數組大小),但即使模板沒有實例化,編譯也失敗了。任何有關如何使其失敗的想法當且僅當基模板函數被實例化時?如何強制使用模板專業化?

template<class Foo> void func(Foo x) { 
    // I want the compiler to complain only if this function is instantiated. 
    // Instead, the compiler is complaining here at the declaration. 
    int Must_Use_Specialization[-1]; 
} 

template<> void func(int x) { 
    printf("Hi\n"); 
} 

回答

1

只需使用Boost.StaticAssert

(編輯:或static_assert,如果你有C++ 11的支持我忘了這一點)。

+1

它應該只是'static_assert'(一個關鍵字,而不是一個庫功能)。 – UncleBens 2012-01-13 17:33:50

+0

更正,謝謝! – Useless 2012-01-15 15:38:26

17

不定義它是最簡單的解決方案:

template<class Foo> void func(Foo x); 

template<> void func(int x) { 
    printf("Hi\n"); 
} 

您還可以在CPP文件和use this將工作定義它們。

而且靜態斷言方法:

template<class Foo> void func(Foo x) { 
    static_assert(sizeof(Foo) != sizeof(Foo), "func must be specialized for this type!"); 
} 
+2

我會將消息更改爲'「func必須專門用於這種類型!」以澄清 – 2012-01-13 17:15:33

+0

我想到了另一種可行的方法。只要引用一個不存在的類成員就是基本函數。 – drwowe 2012-01-13 17:17:22

5

你必須使其依賴於Foo,像這樣:

int Must_Use_Specialization[-sizeof(Foo)]; 
6

在C++ 11可以使用static_assert這樣的:

template<typename T> struct fake_dependency: public std::false_type {}; 
template<class Foo> void func(Foo x) { 
    static_assert(fake_dependency<Foo>::value, "must use specialization"); 
} 

fake_dependency結構是必要的,使斷言依賴在你的模板參數上,所以它等待評估,直到模板被實例化。您可以類似地修復您的解決方案,如下所示:

template<class> struct fake_dependency { enum {value = -1 }; }; 

template<class Foo> void func(Foo x) { 
    int Must_Use_Specialization[fake_dependency<Foo>::value]; 
} 

另請參閱here for a live demo

+0

工作。我還想到了另一種可行的解決方案:引用一個不存在的成員,因此基函數變爲: 模板 void func(Foo x)x.You_must_call_a_specialization_of_this_function; } – drwowe 2012-01-13 17:21:08

+0

@ user1148117:給定無限數量的潛在類,很難保證某些Foo不會有這個成員:) – UncleBens 2012-01-13 17:35:16

+0

另一種在不需要創建附加類型的情況下在模板參數上創建依賴關係的方法是使用'static_assert(sizeof(T)== 0,「...」);'。這是可行的,因爲標準規定每個類型(甚至是空結構)的大小至少爲1.注意,某些編譯器允許以語言擴展的形式使用0長度類型(例如GCC的[「沒有成員的結構」](https ://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Empty-Structures.html))。 – 2015-02-26 10:15:17

3

如果您永遠不會使用它,則不需要基礎模板!只需提供您想要使用的做的類型的過載!

void func(int x) { 
    printf("Hi 1\n"); 
} 

void func(double x) { 
    printf("Hi 2\n"); 
} 

void func(Bar x) { 
    printf("Hi 3\n"); 
} 

這將讓你一個編譯時錯誤func(foo);(除非foo是轉換爲其他類型中的一種)。

+0

爲了更喜歡重載模板功能專業化+1! – AJG85 2012-01-13 18:02:10