C++ 如何从类型列表中为每个继承的类型调用非默认构造函数?
我使用boost类型列表以以下方式实现策略模式C++ 如何从类型列表中为每个继承的类型调用非默认构造函数?,c++,templates,boost,metaprogramming,boost-mpl,C++,Templates,Boost,Metaprogramming,Boost Mpl,我使用boost类型列表以以下方式实现策略模式 using namespace boost::mpl; template <typename PolicyTypeList = boost::mpl::vector<> > class Host : public inherit_linearly<PolicyTypeList, inherit<_1, _2> >::type { public: Host() : m_expensiveTyp
using namespace boost::mpl;
template <typename PolicyTypeList = boost::mpl::vector<> >
class Host : public inherit_linearly<PolicyTypeList, inherit<_1, _2> >::type
{
public:
Host() : m_expensiveType(/* ... */) { }
private:
const ExpensiveType m_expensiveType;
};
是否可以以调用每个给定策略的构造函数的方式定义主机的构造函数?如果不涉及类型列表,这是非常容易的,因为每个策略的类型都是显式已知的
template <typename PolicyA, typename PolicyB>
class Host : public PolicyA, public PolicyB
{
public:
Host() :
m_expensiveType(/* ... */),
PolicyA(m_expensiveType),
PolicyB(m_expensiveType) { }
private:
const ExpensiveType m_expensiveType;
};
模板
班级主持人:公共政策A、公共政策B
{
公众:
主机():
m_expensiveType(/*…*/),
保单A(m_费用类型),
保单B(m_费用类型){}
私人:
const ExpensiveType m_ExpensiveType;
};
该算法看起来很有前途,但我不知道如何使用它来解决这个问题。如评论中所述,您需要链接构造函数调用。为此,派生链中的每个类型都必须知道其派生自什么类型-为了允许任意派生序列,我们需要使该类型成为模板,以便它们的基可以是任何类型。
这允许我们引用基并显式调用其构造函数 我列举了一个基本示例,但最终没有使用boost,因为
mpl::vector
需要已知的类型,我需要将模板参数交给它。相反,我使用了一个支持模板参数并隐式派生的自定义类型列表
struct expensive {};
// derivation list
struct nil {}; // list end
struct Noop { // do nothing on end of derivation chain
Noop(expensive& e) {}
};
template<template <typename T> class H, typename L>
struct DL {
typedef L tail;
typedef H<typename tail::head> head;
};
template<template <typename T> class H>
struct DL<H, nil> {
typedef H<Noop> head;
};
// example types
template<class T>
struct A : T {
A(expensive& e) : T(e) {}
};
template<class T>
struct B : T {
B(expensive& e) : T(e) {}
};
// derivation chain usage example
typedef DL<A, DL<B, nil> > DerivationChain;
class User : DerivationChain::head
{
public:
User(expensive& e) : DerivationChain::head(e) {}
};
int main(int argc, char** argv)
{
expensive e;
User u(e);
}
struct昂贵{};
//派生列表
结构nil{};//列表结束
结构Noop{//在派生链的末尾不执行任何操作
Noop(昂贵的&e){}
};
模板
结构DL{
尾型;
H型头;
};
模板
结构DL{
H型头;
};
//示例类型
模板
结构A:T{
A(昂贵的&e):T(e){}
};
模板
结构B:T{
B(昂贵的&e):T(e){}
};
//派生链用法示例
typedef-DL衍生链;
类用户:派生链::头
{
公众:
用户(昂贵的&e):派生链::头(e){}
};
int main(int argc,字符**argv)
{
昂贵的e;
用户u(e);
}
创建参数化构造函数并将参数传递给它。这样你可以同时完成两件事。
1) 构造函数重载
2) 避免调用默认构造函数。如果您想要这种类型的生成,我只能推荐您阅读Alexandrescu的。有一整章专门讨论从类型列表生成层次结构。你也可以在洛基的网站上找到它:;虽然你会错过图表和解释,以及过程 对于您这个特殊的问题,这似乎非常简单
// Helper
struct nil
{
};
template < class Head, class Tail = nil>
struct SH: Head<Tail> /* for SimpleHierarchy */
{
SH(const ExpensiveType& e): Head(e), SH<Tail>(e) {}
};
template<>
struct SH<nil,nil>
{
SH(const ExpensiveType& e) {}
}:
// Policies
class A
{
public:
A(const ExpensiveType& e) : T(e), m_e(e) {}
private:
const ExpensiveType& m_e;
};
class B
{
public:
B(const ExpensiveType& e) : T(e), m_e(e) {}
private:
const ExpensiveType& m_e;
};
class C
{
public:
C(const ExpensiveType& e) : T(e), m_e(e) {}
private:
const ExpensiveType& m_e;
};
// Use
// nesting example
typedef SH<A, SH<B,C> > SimpleHierarchy;
// Your example, revisited
template <class A, class B>
class Host: SH<A,B>
{
public:
Host(const ExpensiveType& e): SH<A,B>(e), m_e(e) {}
private:
const ExpensiveType& m_e;
};
//助手
结构零
{
};
模板
struct SH:Head/*表示简单层次结构*/
{
SH(施工费用类型和e):主管(e),SH(e){}
};
模板
结构SH
{
SH(const ExpensiveType&e){}
}:
//政策
甲级
{
公众:
A(const ExpensiveType&e):T(e),m_e(e){}
私人:
施工费用类型和m_e;
};
B类
{
公众:
B(const ExpensiveType&e):T(e),m_e(e){}
私人:
施工费用类型和m_e;
};
C类
{
公众:
C(const ExpensiveType&e):T(e),m_e(e){}
私人:
施工费用类型和m_e;
};
//使用
//嵌套示例
类型定义SH简单层次结构;
//你的例子,重温
模板
主持人:上海
{
公众:
主机(const ExpensiveType&e):SH(e),m_e(e){}
私人:
施工费用类型和m_e;
};
当然,这只是一个草图。这里的主要问题是可扩展性。如果你读了Alexandrescu的书,你会学到更多,如果你没有时间,一定要在源代码上达到顶峰,这可能正是你所需要的
有很多方法可以直接从mpl::vector
中执行,唯一需要了解的是,您无法使用大型MI单层来执行此操作,但可以添加许多层
在这里,我选择不在策略级别增加复杂性(它们没有模板化),而是在每个级别依赖MI(dual)。您可以将其完全线性化,但模板化策略意味着您无法在源文件中定义它们
还请注意,这种方法可以调整为直接采用
mpl::vector
,但这将涉及元模板编程操作的使用:back
,pop_back
和empty
,这可能会使代码变得更加混乱,而不是它们实际的帮助。我忍不住想看看如何使用inherit\u
来实现它。
事实证明没那么糟,伊姆霍:
template<class Base, class Self>
struct PolicyWrapper : Base, Self
{
PolicyWrapper(const ExpensiveType& E)
: Base(E), Self(E)
{}
};
struct EmptyWrapper
{
EmptyWrapper(const ExpensiveType& E)
{}
};
template <typename PolicyTypeList = boost::mpl::vector<> >
class Host :
public inherit_linearly<
PolicyTypeList,
PolicyWrapper<_1, _2>,
EmptyWrapper
>::type
{
typedef typename inherit_linearly<
PolicyTypeList,
PolicyWrapper<_1, _2>,
EmptyWrapper
>::type BaseType;
public:
Host() : BaseType(m_expensiveType)
{}
private:
const ExpensiveType m_expensiveType;
};
糟糕的事情会发生,因为ExpensiveType的复制子将被一个未初始化的对象调用。你不能以这样的方式定义
Host
,因为inherit\u线性地
构建了一个“继承链”,你必须以某种方式链接构造函数调用,也就是说,让Host
为最派生的对象调用它,最容易派生的是下一个,等等。问题不是关于基本构造函数的用法。这个想法简单而有效,尽管head的使用似乎有点尴尬。不是很完美的imho。我知道,这只是一个快速的方法来传达这个想法。双MI方法肯定会让它更干净,因为它不会将派生语义混合到策略中。看起来struct SH:Head
应该是struct SH:Head,SH
?调用未初始化类型的复制构造函数非常好。为了安全起见,最好是传递一个指针。@Steve:嗯,传递一个指针到一个未初始化的类型并没有太大的不同。它可能更强烈地表明对象具有引用(而不是值)语义,并防止我在回答中显示的错误,但实际上,指针的接收者可以对指向的对象做任何事情,就像对引用一样。@Narfanator:我不确定您实际上在寻找什么,但是让我试试。请告诉我这是否回答了这个问题:inherit_linear::type
可以被视为类似于std::acculate
:它需要一个序列(类型)和一个初始值(Ro)
template<class Base, class Self>
struct PolicyWrapper : Base, Self
{
PolicyWrapper(const ExpensiveType& E)
: Base(E), Self(E)
{}
};
struct EmptyWrapper
{
EmptyWrapper(const ExpensiveType& E)
{}
};
template <typename PolicyTypeList = boost::mpl::vector<> >
class Host :
public inherit_linearly<
PolicyTypeList,
PolicyWrapper<_1, _2>,
EmptyWrapper
>::type
{
typedef typename inherit_linearly<
PolicyTypeList,
PolicyWrapper<_1, _2>,
EmptyWrapper
>::type BaseType;
public:
Host() : BaseType(m_expensiveType)
{}
private:
const ExpensiveType m_expensiveType;
};
struct BadPolicy
{
BadPolicy(const ExpensiveType& E)
: m_expensiveType(E)
{}
ExpensiveType m_expensiveType;
};