模板约束C++

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_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");

        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 完善!*我需要更多角色......* (5认同)

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()),那么我们会得到可怕的六页模板编译时错误.

  • “然后我们得到了可怕的六页模板编译时错误”(大声笑),因此,我们所有人都在等待神圣的“概念”概念。 (3认同)

luk*_*uke 34

正如其他人提到的那样,C++ 0x正在将其内置于该语言中.在那之前,我会推荐Bjarne Stroustrup 关于模板约束建议.

编辑:Boost也有自己替代品.

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

  • ......可能还加入了[C++ 1y](http://stackoverflow.com/questions/15669592/what-are-the-differences-between-concepts-and-template-constraints) (2认同)
  • [约束和概念](https://en.cppreference.com/w/cpp/language/constraints)将在c ++ 20中添加 (2认同)

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;

正如您可以想象的那样,此功能非常有用,并且可以做的不仅仅是限制类具有特定的基数。


Nem*_*vic 8

查看Boost

Boost概念检查库(BCCL)

概念检查库允许以建议的C++语言扩展的样式添加显式语句和概念检查.