模板约束C ++

在C#中,我们可以定义一个通用types,对可以用作generics参数的types施加约束。 以下示例说明了通用约束的用法:

interface IFoo { } class Foo<T> where T : IFoo { } class Bar : IFoo { } class Simpson { } class Program { static void Main(string[] args) { Foo<Bar> a = new Foo<Bar>(); Foo<Simpson> b = new Foo<Simpson>(); // error CS0309 } } 

有没有一种方法可以在C ++中对模板参数施加约束。


C ++ 0x有本地支持,但我正在谈论当前的标准C ++。

正如其他人所提到的,C ++ 0x正在把这个内置到语言中。 在此之前,我build议Bjarne Stroustrup 对模板约束的build议 。

编辑: 提升也有其自己的替代 。

Edit2:看起来像概念已经从C ++ 0x中删除 。

“含蓄”是正确的答案。 由于模板的编译方式,模板有效地创build了“鸭子打字”的场景。 你可以使用模板types的值来调用你想要的任何函数,唯一可以接受的实例就是定义该方法的那些实例。 例如:

 template <class T> int compute_length(T *value) { return value->length(); } 

我们可以在一个指向任何声明length()方法返回一个inttypes的指针上调用这个方法。 正是如此:

 string s = "test"; vector<int> vec; int i = 0; compute_length(&s); compute_length(&vec); 

…而不是指向声明length()的types的指针:

 compute_length(&i); 

这第三个例子不会编译。

这是有效的,因为C ++为每个实例化编译了模板化函数(或类)的新版本。 执行该编译时,在进行types检查之前,它将模板实例化直接,近似macros观地replace为代码。 如果所有东西都仍然适用于这个模板,那么编译就会继续,最终我们会得出结果。 如果任何失败(如int*不声明length() ),那么我们得到了可怕的六页模板编译时错误。

如果你使用C ++ 11,你可以使用static_assertstd::is_base_of来达到这个目的。

例如,

 #include <type_traits> template<typename T> class YourClass { YourClass() { // Compile-time check static_assert(std::is_base_of<BaseClass, T>::value, "type parameter of this class must derive from BaseClass"); // ... } } 

你可以在IFoo上放置一个不做任何事的警卫types,确保它在Foo中的T:

 class IFoo { public: typedef int IsDerivedFromIFoo; }; template <typename T> class Foo<T> { typedef typename T::IsDerivedFromIFoo IFooGuard; } 

检查提升

提升概念检查图书馆(BCCL)

Concept Check库允许添加显式语句并以提议的C ++语言扩展的风格检查概念 。

有点。 如果将static_cast传送给IFoo *,则不可能实例化模板,除非调用者传递了可分配给IFoo *的类。

只是隐含的。
您在实际调用的方法中使用的任何方法都强加在模板参数上。

你能行的。 创build基本模板。 使它只有私人构造函数。 然后为每个要允许的情况创build专门化(如果不允许的列表比允许的列表小得多,则做相反的处理)。

编译器将不允许您使用私有构造函数实例化使用该版本的模板。

这个例子只允许用int和float实例化。

 template<class t> class FOO { private: FOO(){}}; template<> class FOO<int>{public: FOO(){}}; template<> class FOO<float>{public: FOO(){}}; 

它不是一个简短而优雅的做法,但它是可能的。

看看CRTP模式(好奇recursion模板模式)。 它旨在帮助支持静态的inheritance。