Jor*_*ira 62 c++ templates constraints
在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
}
}
Run Code Online (Sandbox Code Playgroud)
有没有办法可以在C++中对模板参数施加约束.
C++ 0x本身支持这个,但我说的是当前的标准C++.
Ven*_*emo 58
如果您使用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");
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
Dan*_*wak 37
"隐晦地"是正确的答案.由于编译方式,模板有效地创建了"鸭子打字"场景.您可以在模板类型值上调用所需的任何函数,并且唯一可以接受的实例是为其定义该方法的实例.例如:
template <class T>
int compute_length(T *value)
{
return value->length();
}
Run Code Online (Sandbox Code Playgroud)
我们可以在指向任何声明length()方法返回的类型的指针上调用此方法int.正是如此:
string s = "test";
vector<int> vec;
int i = 0;
compute_length(&s);
compute_length(&vec);
Run Code Online (Sandbox Code Playgroud)
...但不是指向未声明的类型的指针length():
compute_length(&i);
Run Code Online (Sandbox Code Playgroud)
第三个例子不会编译.
这是有效的,因为C++为每个实例化编译了一个新版本的模板化函数(或类).当它执行该编译时,它在类型检查之前将模板实例化直接,几乎像宏一样替换到代码中.如果一切仍然适用于该模板,则编译继续进行,我们最终得出结果.如果有任何失败(如int*没有声明length()),那么我们会得到可怕的六页模板编译时错误.
luk*_*uke 34
正如其他人提到的那样,C++ 0x正在将其内置于该语言中.在那之前,我会推荐Bjarne Stroustrup 关于模板约束的建议.
Edit2:看起来概念已从C++ 0x中删除.
Ecl*_*pse 15
你可以在IFoo上放一个什么都不做的防护类型,确保它在Foo的T上有:
class IFoo
{
public:
typedef int IsDerivedFromIFoo;
};
template <typename T>
class Foo<T>
{
typedef typename T::IsDerivedFromIFoo IFooGuard;
}
Run Code Online (Sandbox Code Playgroud)
小智 11
使用 C++20,是的,有:约束和概念
也许您想保证模板派生自特定类:
#include <concepts>
template<class T, class U>
concept Derived = std::is_base_of<U, T>::value;
class ABase { };
class ADerived : ABase { };
template<Derived<ABase> T>
class AClass {
T aMemberDerivedFromABase;
};
Run Code Online (Sandbox Code Playgroud)
然后像正常一样编译以下内容:
int main () {
AClass<ADerived> aClass;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但现在当你做一些违反约束的事情时:
class AnotherClass {
};
int main () {
AClass<AnotherClass> aClass;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
AnotherClass 不是从 ABase 派生的,因此我的编译器(GCC)大致给出以下错误:
在函数“int main()”中:注意:不满足约束注意:表达式“std::is_base_of<U, T>::value [with U = ABase; T = AnotherClass]' 评估为“假”9 | 概念派生 = std::is_base_of<U, T>::value;
正如您可以想象的那样,此功能非常有用,并且可以做的不仅仅是限制类具有特定的基数。