模板约束C ++

时间:2020-03-06 14:36:43  来源:igfitidea点击:

在Cwe中,可以定义一个通用类型,该通用类型对可用作通用参数的类型施加了约束。以下示例说明了通用约束的用法:

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

解决方案

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

退房升压

The Boost Concept Check Library (BCCL)
  
  The Concept Check library allows one to add explicit statement and checking of concepts in the style of the proposed C++ language extension.

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

正如其他人提到的那样,C ++ 0x正在将其内置到语言中。在此之前,我将建议Bjarne Stroustrup针对模板约束提出建议。

编辑:Boost也有自己的替代方案。

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

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

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

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

class IFoo
{
public:
    typedef int IsDerivedFromIFoo;
};

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

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

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

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

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

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

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

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

查看CRTP模式(好奇地递归模板模式)。它旨在帮助支持静态继承。