在C#中,我们可以定义一个泛型类型,它对可用作泛型参数的类型施加约束。以下示例说明了通用约束的用法:
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 ++。
答案 0 :(得分:49)
如果您使用C ++ 11,则可以将static_assert
与std::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");
// ...
}
}
答案 1 :(得分:34)
“隐含”是正确的答案。由于编译方式,模板有效地创建了“鸭子打字”场景。您可以在模板类型值上调用所需的任何函数,并且唯一可以接受的实例是为其定义该方法的实例。例如:
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()
),那么我们会得到可怕的六页模板编译时错误。
答案 2 :(得分:33)
正如其他人所提到的,C ++ 0x正在将此内置于该语言中。在此之前,我建议Bjarne Stroustrup的suggestions for template constraints。
修改:Boost也有alternative of its own。
Edit2:看起来像concepts have been removed from C++0x。
答案 3 :(得分:14)
你可以在IFoo上放一个什么都不做的保护类型,确保它在Foo的T上有:
class IFoo
{
public:
typedef int IsDerivedFromIFoo;
};
template <typename T>
class Foo<T>
{
typedef typename T::IsDerivedFromIFoo IFooGuard;
}
答案 4 :(得分:8)
查看Boost
Boost概念检查库(BCCL)
概念检查库允许我们以concepts的样式添加显式语句和proposed C++ language extension检查。
答案 5 :(得分:2)
排序。如果你static_cast到IFoo *,那么除非调用者传递一个可以分配给IFoo *的类,否则将无法实例化模板。
答案 6 :(得分:1)
只是含蓄地 您在实际调用的方法中使用的任何方法都强加于模板参数。
答案 7 :(得分:0)
你可以做到。创建基本模板。使它只有私有构造函数。然后为您想要允许的每个案例创建特化(或者如果不允许的列表比允许的列表小得多,则相反)。
编译器不允许您实例化使用私有构造函数的模板。
此示例仅允许使用int和float进行实例化。
template<class t> class FOO { private: FOO(){}};
template<> class FOO<int>{public: FOO(){}};
template<> class FOO<float>{public: FOO(){}};
它不是一种简短而优雅的方式,但它可能。
答案 8 :(得分:-1)
查看CRTP模式(奇怪的递归模板模式)。它旨在帮助支持静态继承。