Use Curiously Recurring Template Pattern (CRTP) with additional type parameters
我尝试使用奇怪的循环模板模式(crtp)并提供其他类型参数:
1 2 3 4 5 6 7 8 9 | template <typename Subclass, typename Int, typename Float> class Base { Int *i; Float *f; }; ... class A : public Base<A, double, int> { }; |
这可能是一个bug,更合适的超类应该是
1 2 3 4 5 6 7 8 9 10 | template <typename Subclass> class Base { typename Subclass::Int_t *i; // error: invalid use of incomplete type ‘class A’ typename Subclass::Float_t *f; }; class A : public Base<A> { typedef double Int_t; // error: forward declaration of ‘class A’ typedef int Double_t; }; |
然而,这并不是在GCC4.4上编译的,报告的错误是作为上面的注释给出的——我认为原因是在创建之前,它需要实例化基本模板,但这反过来又需要知道A。
在使用crtp时,有没有一种好的传入"已命名"模板参数的方法?
你可以使用特征类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // Must be specialized for any type used as TDerived in Base<TDerived>. // Each specialization must provide an IntType typedef and a FloatType typedef. template <typename TDerived> struct BaseTraits; template <typename TDerived> struct Base { typename BaseTraits<TDerived>::IntType *i; typename BaseTraits<TDerived>::FloatType *f; }; struct Derived; template <> struct BaseTraits<Derived> { typedef int IntType; typedef float FloatType; }; struct Derived : Base<Derived> { }; |
@James的回答显然是正确的,但是如果用户没有提供正确的typedef,您仍然可能会遇到一些问题。
可以使用编译时检查工具"断言"所使用的类型是正确的。根据你使用的C++版本,你必须使用Boost。
在C++ 0x中,这是结合的:
static_assert :一种新的编译时检查工具,让您指定一条消息type_traits 头,它提供一些谓词,如std::is_integral 或std::is_floating_point 。
例子:
1 2 3 4 5 6 7 8 9 10 11 12 | template <typename TDerived> struct Base { typedef typename BaseTraits<TDerived>::IntType IntType; typedef typename BaseTraits<TDerived>::FloatType FloatType; static_assert(std::is_integral<IntType>::value, "BaseTraits<TDerived>::IntType should have been an integral type"); static_assert(std::is_floating_point<FloatType>::value, "BaseTraits<TDerived>::FloatType should have been a floating point type"); }; |
这与运行时世界中典型的防御编程习惯非常相似。
实际上你甚至不需要特征类。以下内容也有效:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | template < typename T1, typename T2, template <typename, typename> class Derived_ > class Base { public: typedef T1 TypeOne; typedef T2 TypeTwo; typedef Derived_<T1, T2> DerivedType; }; template <typename T1, typename T2> class Derived : public Base<T1, T2, Derived> { public: typedef Base<T1, T2, Derived> BaseType; // or use T1 and T2 as you need it }; int main() { typedef Derived<int, float> MyDerivedType; MyDerivedType Test; return 0; } |