通过CRTP和多重继承消除冗余 [英] Eliminate redundancy with CRTP and multiple inheritance
问题描述
这个问题是针对C ++ 03的,而不是针对C ++ 11的.
This question is for C++03, not C++11.
在某些情况下,我正在使用具有多重继承的CRTP,并且我很想知道是否有一种方法可以删除在指定以下B
类型时创建的冗余.
I have a case where I am using CRTP with multiple inheritance, and I am curious to know if there is a way to remove the redundancy that is created when specifying the type of B
below.
#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
或某些等效的this
编译时版本的继承列表中访问typedef B<T1, T2, T3> Self
的方法.
The problem worsens when the number of template parameters for B
increases, when the template arguments themselves are complex, and when B
inherits from A
more times. I'd like to minimize the repetition of B
's template parameters. Specifically, I am looking for a way to access the typedef B<T1, T2, T3> Self
up in the inheritance list for B
, or some equivalent compile-time version of this
.
我不能:
- 使用前向声明为
B
以上的B
输入typedef,因为我无权访问模板参数 - 在继承定义中添加typedef ,因为语法不允许这样做
- 从类内部访问typedef,因为它尚不存在
- Make a typedef for
B
aboveB
using a forward declaration, because I don't have access to the template parameters - Make a typedef inside of the inheritance definition because the syntax doesn't allow that
- Access the typedef from inside the class, because it doesn't exist yet
类似下面的内容(都不是有效的代码,但是会显示我想要的效果):
Something like the below (none of which are not valid code, but display the effect I am looking for):
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
的编译时版本?
Is there a way to access a compile-time version of 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
一个 type 实例化,而您希望做的是
用T2
一个 template 实例化它,即
template<typename, typename,typename> struct B
.
is that your template <typename T1, typename T2> struct A
asks to
be instantiated with T2
a type, whereas what you wish you could do
is instantiate it with T2
a template, namely
template<typename, typename,typename> struct B
.
如果A
的定义位于您自己的控件中,那么也许(尽管可能不是)一种解决方案
使A
的定义与您的愿望保持一致:
If the definition of A
lies in your own control, then perhaps - though perhaps not - a solution
is to make the definition of A
consistent with your wish:
#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
参数.
The price of this solution is restricting the classes for which
A
can furnish a CRTP base to ones that instantiate a template, like
B
, of exactly three typename
parameters.
也许您很幸运,这个限制不会阻止任何其他限制
希望你有.但是如果您还需要A
来提供CRTP基础
对于实例化某些模板的类,这些模板不完全具有三个
typename
参数,然后咬.
Perhaps you are lucky enough that this restriction does not thwart any other
wishes you have. But if you also need A
to furnish a CRTP base
for classes that instantiate some template that does not have exactly three
typename
parameters, then it bites.
提供了您需要A
为其提供CRTP的所有类
base是仅具有typename
参数的模板的实例,
并且最多有N
个,那么您仍然可以在其中使用C ++ 03解决方案
相同的精神:
Provided that all of the classes for which you need A
to furnish a CRTP
base are instantiations of templates that have only typename
parameters,
and have at most N
of them, then you can still have a C++03 solution in the
same spirit:
您根据架构定义A
:
template<typename T1,
template<typename /*1*/,.... typename /*N*/> class T2
>
struct A { ... };
对于以A
为CRTP基础的每个模板Y
,您需要提供
完全N
参数,采用默认的填充"参数
void
,如有必要.例如,如果N
== 3:
And for each template Y
for which A
is to be a CRTP base, you provide
exactly N
parameters, employing "padding" parameters that default to
void
, as necessary. For example, if 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>
是的,更一般的解决方案使您陷入另一种冗余"状态, 这些多余的默认模板参数的形式.但是你 可能会发现它不太讨厌.
True, the more general solution sticks you with a different kind of "redundancy", in the form of those superfluous defaulted template parameters. But you may find it a less irksome kind.
(gcc 5.1/clang 3.6,C ++ 03)
(gcc 5.1/clang 3.6, C++03)
这篇关于通过CRTP和多重继承消除冗余的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!