模板约束C ++
在Cwe中,可以定义一个通用类型,该通用类型对可用作通用参数的类型施加了约束。以下示例说明了通用约束的用法:
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 ++。
解决方案
仅暗含。
我们在实际调用的方法中使用的任何方法都会强加给template参数。
退房升压
The Boost Concept Check Library (BCCL) The Concept Check library allows one to add explicit statement and checking of concepts in the style of the proposed C++ language extension.
有点。如果我们static_cast到IFoo *,那么除非调用者传递可以分配给IFoo *的类,否则将无法实例化模板。
正如其他人提到的那样,C ++ 0x正在将其内置到语言中。在此之前,我将建议Bjarne Stroustrup针对模板约束提出建议。
编辑:Boost也有自己的替代方案。
Edit2:看起来像概念已从C ++ 0x中删除。
"隐式"是正确的答案。模板由于其编译方式而有效地创建了"鸭子输入"方案。我们可以在模板类型的值上调用所需的任何函数,并且唯一接受的实例是为其定义了该方法的实例。例如:
template <class T> int compute_length(T *value) { return value->length(); }
我们可以在指向任何声明" length()"方法以返回" int"的类型的指针上调用此方法。因此:
string s = "test"; vector<int> vec; int i = 0; compute_length(&s); compute_length(&vec);
...但不在指向未声明length()
的类型的指针上:
compute_length(&i);
第三个示例将无法编译。
之所以可行,是因为C ++会为每个实例编译新版本的模板化函数(或者类)。在执行编译时,它会在类型检查之前将模板实例直接,几乎像宏一样替换为代码。如果一切仍然适用于该模板,则编译会继续进行,我们最终会得出结果。如果任何事情失败(例如int *没有声明length()),那么我们将得到可怕的六页模板编译时错误。
我们可以在不执行任何操作的IFoo上放置一个保护类型,确保它在Foo中的T上存在:
class IFoo { public: typedef int IsDerivedFromIFoo; }; template <typename T> class Foo<T> { typedef typename T::IsDerivedFromIFoo IFooGuard; }
你能行的。创建基本模板。使它仅具有私有构造函数。然后为要允许的每种情况创建专门化名称(如果不允许的列表比允许的列表小得多,则进行相反的处理)。
编译器不允许我们实例化使用带有私有构造函数的版本的模板。
本示例仅允许使用int和float实例化。
template<class t> class FOO { private: FOO(){}}; template<> class FOO<int>{public: FOO(){}}; template<> class FOO<float>{public: FOO(){}};
这不是一种简短而优雅的方法,但有可能。
查看CRTP模式(好奇地递归模板模式)。它旨在帮助支持静态继承。