代码之家  ›  专栏  ›  技术社区  ›  Jorge Ferreira

模板约束C++

  •  57
  • Jorge Ferreira  · 技术社区  · 16 年前

    在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 回复  |  直到 8 年前
        1
  •  33
  •   James Adkison    9 年前

    正如其他人提到的,C++0X正是把它内置到语言中的。在那之前,我建议 Bjarne Stroustrup suggestions for template constraints .

    编辑: Boost 也有一个 alternative of its own .

    编辑2:看起来像 concepts have been removed from C++0x .

        2
  •  48
  •   Venemo    8 年前

    如果你使用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");
    
            // ...
        }
    }
    
        3
  •  34
  •   Daniel Spiewak    16 年前

    “含蓄地”是正确的答案。模板有效地创建了一个“duck-typing”场景,这是由于它们的编译方式。您可以对模板类型的值调用任何您想要的函数,唯一可以接受的实例化是为其定义该方法的实例化。例如:

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

    …但不在指向类型的指针上 声明 长度() :

    compute_length(&i);
    

    第三个例子不会编译。

    这是因为C++为每个实例化编译了一个新版本的模板化函数(或类)。在执行编译的过程中,它在类型检查之前直接、几乎像宏一样将模板实例化替换为代码。如果所有东西都能用这个模板工作,那么编译就会继续进行,我们最终会得到一个结果。如果有什么失败(比如 int* 不申报 长度() ,然后我们得到了可怕的六页模板编译时错误。

        4
  •  14
  •   Salman A    16 年前

    你可以在没有任何作用的情况下设置一个防护类型,确保它在foo的t上:

    class IFoo
    {
    public:
        typedef int IsDerivedFromIFoo;
    };
    
    template <typename T>
    class Foo<T>
    {
        typedef typename T::IsDerivedFromIFoo IFooGuard;
    }
    
        5
  •  8
  •   Félix Adriyel Gagnon-Grenier    10 年前

    退房 Boost

    Boost概念检查库(BCCL)

    概念检查库允许添加显式语句并检查 concepts proposed C++ language extension .

        6
  •  2
  •   Lou Franco    16 年前

    某种程度上。如果静态转换为ifoo*,那么除非调用方传递一个可以分配给ifoo*的类,否则将无法实例化模板。

        7
  •  1
  •   shoosh    16 年前

    只是含蓄地。
    您在实际调用的方法中使用的任何方法都会强加于模板参数。

        8
  •  0
  •   Salman A    14 年前

    你可以做到。创建基本模板。使其仅具有私有构造函数。然后为您希望允许的每种情况创建专门化(或者,如果不允许的列表比允许的列表小得多,则创建相反的专门化)。

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

    这个例子只允许用int和float进行实例化。

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

    这不是一种短小精悍的方式,而是可能的。

        9
  •  -1
  •   RHss    16 年前

    看看CRTP模式(奇怪的是递归模板模式)。它旨在帮助支持静态继承。