2011-08-15 19 views
31

我有一个模板class(称为Foo),它有几个专业。如果有人试图使用Foo的非专用版本,我希望编译失败。如何防止非专用模板实例化?

这是我实际上有:

template <typename Type> 
class Foo 
{ 
    Foo() { cannot_instantiate_an_unspecialized_Foo(); } 

    // This method is NEVER defined to prevent linking. 
    // Its name was chosen to provide a clear explanation why the compilation failed. 
    void cannot_instantiate_an_unspecialized_Foo(); 
}; 

template <> 
class Foo<int> 
{ }; 

template <> 
class Foo<double> 
{ }; 

这样:

int main() 
{ 
    Foo<int> foo; 
} 

作品,同时:

int main() 
{ 
    Foo<char> foo; 
} 

没有。

显然,编译器链只会在链接过程发生时发出抱怨。但是有没有办法让它抱怨?可以使用boost

回答

35

只是不定义类:

template <typename Type> 
class Foo; 

template <> 
class Foo<int> { }; 

int main(int argc, char *argv[]) 
{ 
    Foo<int> f; // Fine, Foo<int> exists 
    Foo<char> fc; // Error, incomplete type 
    return 0; 
} 

为什么这项工作?只是因为不是任何通用模板。宣布,是的,但没有定义。

+1

非常感谢。我想我正在寻找一些太复杂的东西。 – ereOn

+0

@Schnommus但是如果你确实定义了类并且它有一个static_assert,它不应该永远不会被实例化,因为专业化比较好? –

+0

这是不好的决定,因为连接阶段会发出错误,而不是编译。你永远不会知道你在哪里使用非专业课程。 – vladon

17

你可以简单地不能定义基本情况:

template <typename> class Foo;    // no definition! 

template <> class Foo<int> { /* ... */ }; // Foo<int> is OK 
+6

我不敢相信我错过了...谢谢。接受Schnommus答案是因为他声誉较低。 Upvoted这个公平。 – ereOn

13

一种的C++ 0x(也​​可以用C++ 03 static_assert仿真,但错误信息诀窍是不一定好不是把初级模板未定义):

template<typename T> 
struct dependent_false: std::false_type {}; 

template<typename Type> 
struct Foo { 
    static_assert(dependent_false<Type>::value 
       , "Only specializations of Foo may be used"); 
}; 

断言只会触发时Foo被实例化与主模板。使用static_assert(false, ...)将始终触发断言。

+0

+1。谢谢你的诀窍。 – ereOn

+2

需要更少类型的类似技巧是使用static_assert(sizeof(Type)== 0,“...”);作为替代方案,您可以使用BOOST_STATIC_ASSERT。我个人更喜欢那些,因为上面的“不定义基本模板”可能会导致链接器错误,当您只使用引用/指针时。通常你应该停下来一会儿,重新考虑一下你是否真的需要这个,因为模板是通用的,你在这里限制 – PlasmaHH

+0

这是如何工作的?您是否需要为每个“专业化”定义'dependent_false :std :: true_type {}',否则'dependent_false :: value'将始终为假? – mako