使用 CRTP 和多重继承消除冗余

Eliminate redundancy with CRTP and multiple inheritance

此问题针对 C++03,而非 C++11。

我有一个案例,我正在使用具有多重继承的 CRTP,我很想知道是否有办法删除在下面指定 B 类型时创建的冗余。

#include "boost/typeof/typeof.hpp"
#include "boost/units/detail/utility.hpp"
#include <iostream>
#include <string>

struct One{};
struct Two{};

template<typename T>
struct Type
{
   static std::string name(void)
   {
      return boost::units::detail::demangle(typeid(T).name());
   }
};

template<typename T1,
         typename T2>
struct A
{
   typedef A<T1, T2> Self;

   A()
   {
      std::cout << Type<Self>::name() << std::endl;
   }
};

template<typename T1,
         typename T2,
         typename T3>
struct B : public A<One, B<T1, T2, T3> >, // The B<T1, T2, T3> here is redundant
           public A<Two, B<T1, T2, T3> >
{
   typedef B<T1, T2, T3> Self;

   B()
   {
      std::cout << Type<Self>::name() << std::endl;
   }
};

int main(int argc, char* argv[])
{
   B<int, int, int> t;
   return 0;
}

Coliru

上看到这个

B 的模板参数数量增加、模板参数本身很复杂以及 BA 继承更多次时,问题会变得更糟。我想尽量减少 B 模板参数的重复。具体来说,我正在寻找一种方法来访问 B 的继承列表中的 typedef B<T1, T2, T3> Selfthis 的某些等效编译时版本。

我不能:

类似下面的内容(none 不是有效代码,但显示了我正在寻找的效果):

template<typename T1,
         typename T2,
         typename T3>
struct B : public A<One, Self>, // Cannot access the typedef yet
           public A<Two, Self>
{
   typedef B<T1, T2, T3> Self;
};

template<typename T1,
         typename T2,
         typename T3>
struct B : typedef B<T1, T2, T3> Self, // Invalid syntax
           public A<One, Self>, 
           public A<Two, Self>
{

};

template<typename T1,
         typename T2,
         typename T3>
struct B : public A<One, B>, // I wish this would work
           public A<Two, B>
{

};

template<typename T1,
         typename T2,
         typename T3>
struct B : public A<One, BOOST_TYPEOF(*this)>, // lol
           public A<Two, BOOST_TYPEOF(*this)>
{

};

有没有办法访问 this 的编译时版本?

问题在于:

template<typename T1,
         typename T2,
         typename T3>
struct B : public A<One, B>, // I wish this would work
           public A<Two, B>
{

};

是你的template <typename T1, typename T2> struct A要求 用 T2 a type 实例化,而你希望你能做什么 用 T2 a template 实例化它,即 template<typename, typename,typename> struct B.

如果 A 的定义在你自己的掌控之中,那么也许——尽管也许不是——一个解决方案 就是让A的定义符合你的意愿:

#include "boost/typeof/typeof.hpp"
#include "boost/units/detail/utility.hpp"
#include <iostream>
#include <string>

struct One{};
struct Two{};

template<typename T>
struct Type
{
   static std::string name(void)
   {
      return boost::units::detail::demangle(typeid(T).name());
   }
};

template<typename T1,
         template<typename, typename, typename> class T2
>
struct A
{

   A()
   {
      std::cout << Type<A>::name() << std::endl;
   }
};


template<typename T1,
         typename T2,
         typename T3>
struct B : public A<One, B >,
           public A<Two, B >
{
   B()
   {
      std::cout << Type<B>::name() << std::endl;
   }
};


int main(int argc, char* argv[])
{
   B<int, int, int> t;
   return 0;
}

这个程序打印:

A<One, B>
A<Two, B>
B<int, int, int>

此解决方案的价格限制了 类 A 可以为实例化模板的提供 CRTP 基础,例如 B,正好三个 typename 个参数。

也许你很幸运,这个限制不会阻碍任何其他 希望你有。但是如果你还需要 A 来提供一个 CRTP 基础 for 类 实例化一些不完全是三个的模板 typename 参数,然后它咬。

前提是您需要 A 的所有 类 来提供 CRTP base 是只有 typename 参数的模板实例, 并且最多有 N 个,那么你仍然可以在 同样的精神:

您根据架构定义 A

template<typename T1,
         template<typename /*1*/,.... typename /*N*/> class T2
>
struct A { ... };

并且对于 A 作为 CRTP 基础的每个模板 Y,您提供 恰好 N 个参数,使用默认为 "padding" 个参数 void,如有必要。例如,如果 N == 3:

#include "boost/typeof/typeof.hpp"
#include "boost/units/detail/utility.hpp"
#include <iostream>
#include <string>

struct One{};
struct Two{};

template<typename T>
struct Type
{
   static std::string name(void)
   {
      return boost::units::detail::demangle(typeid(T).name());
   }
};

template<typename T1,
         template<typename, typename, typename> class T2
>
struct A
{

   A()
   {
      std::cout << Type<A>::name() << std::endl;
   }
};


template<typename T1, typename T2 = void, typename T3 = void>
struct B : public A<One, B >,
           public A<Two, B >
{
   B()
   {
      std::cout << Type<B>::name() << std::endl;
   }
};

template<typename T1, typename T2, typename T3 = void>
struct C : public A<One, C >,
           public A<Two, C >
{
   C()
   {
      std::cout << Type<C>::name() << std::endl;
   }
};

template<typename T1, typename T2, typename T3>
struct D : public A<One, D >,
           public A<Two, D >
{
   D()
   {
      std::cout << Type<D>::name() << std::endl;
   }
};



int main(int argc, char* argv[])
{
   B<int> b;
   C<int,int> c;
   D<int,int,int> d;
   return 0;
}

这个程序打印:

A<One, B>
A<Two, B>
B<int, void, void>
A<One, C>
A<Two, C>
C<int, int, void>
A<One, D>
A<Two, D>
D<int, int, int>

是的,更通用的解决方案会让你陷入另一种 "redundancy",在 那些多余的默认模板参数的形式。但是你 可能会觉得它不那么令人厌烦。

(gcc 5.1/clang 3.6, C++03)