使用 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
的模板参数数量增加、模板参数本身很复杂以及 B
从 A
继承更多次时,问题会变得更糟。我想尽量减少 B
模板参数的重复。具体来说,我正在寻找一种方法来访问 B
的继承列表中的 typedef B<T1, T2, T3> Self
或 this
的某些等效编译时版本。
我不能:
- 使用前向声明为
B
以上 B
创建 typedef,因为我无权访问模板参数
- 在继承定义中创建一个类型定义,因为语法不允许
- 从 class 中访问 typedef,因为它还不存在
类似下面的内容(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)
此问题针对 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
的模板参数数量增加、模板参数本身很复杂以及 B
从 A
继承更多次时,问题会变得更糟。我想尽量减少 B
模板参数的重复。具体来说,我正在寻找一种方法来访问 B
的继承列表中的 typedef B<T1, T2, T3> Self
或 this
的某些等效编译时版本。
我不能:
- 使用前向声明为
B
以上B
创建 typedef,因为我无权访问模板参数 - 在继承定义中创建一个类型定义,因为语法不允许
- 从 class 中访问 typedef,因为它还不存在
类似下面的内容(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)