模板约束C ++

时间:2008-09-23 17:03:14

标签: 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
    }
}

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


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

9 个答案:

答案 0 :(得分:49)

如果您使用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");

        // ...
    }
}

答案 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 Stroustrupsuggestions 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模式(奇怪的递归模板模式)。它旨在帮助支持静态继承。