模板约束C ++


71

在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 ++。


正如Nemanja所说,Boost具有一个实现类似功能的库。比它本来是适当的语言功能要冗长一些,但是它可以工作,并且可以表达大多数约束。
jalf

Answers:



66

如果使用C ++ 11,则可以使用static_assertwithstd::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");

        // ...
    }
}

6
完善!而且我需要更多角色...
3Dave

这对于编译时错误很有帮助,但实际上并不是一个约束。例如,约束可以使您使模板过载all arithmetic types,以便编译器可以根据约束在两个模板之间进行选择。
Troyseph

40

“隐式”是正确的答案。模板由于其编译方式而有效地创建了“鸭子输入”方案。您可以在模板类型的值上调用所需的任何函数,唯一接受的实例是为其定义了该方法的实例。例如:

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


1
我想您是说在评论中写就足够了吗? //T must inherit from BaseA, otherwise compilation will fail
bobobobo

3
then we get the dreaded six page template compile-time error因此,我们都在等待神圣的“概念”概念。
TechNyquist

16

您可以在不执行任何操作的IFoo上放置一个保护类型,确保它在Foo中的T上存在:

class IFoo
{
public:
    typedef int IsDerivedFromIFoo;
};

template <typename T>
class Foo<T>
{
    typedef typename T::IsDerivedFromIFoo IFooGuard;
}


2

有点。如果您static_cast到IFoo *,那么除非调用者传递可以分配给IFoo *的类,否则无法实例化模板。


1

仅暗含。
您在实际调用的方法中使用的任何方法都会强加给template参数。


0

你能行的。创建基本模板。使它只有私有构造函数。然后为要允许的每种情况创建专门化名称(如果不允许的列表比允许的列表小得多,则相反)。

编译器不允许您实例化使用带有私有构造函数的版本的模板。

本示例仅允许使用int和float实例化。

template<class t> class FOO { private: FOO(){}};

template<> class FOO<int>{public: FOO(){}};

template<> class FOO<float>{public: FOO(){}};

这不是一种简短而优雅的方法,但有可能。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.