我正在尝试使用C ++ Mixins,但是,我的工作创建的工厂遵循与创建的项目相同的层次结构。
我在按正确的顺序扩展工厂创建函数和构造函数时遇到问题。
例如:
template<class BaseT>
class MixInA : public BaseT
{
public:
template <class... Args>
void MixInA(double a, Args&&... args) { m_a(a), Base(std::forward<Args>(args)...); }
double m_a;
}
template<class FactoryBaseT>
class FactoryMixInA : public FactoryBaseT
{
public:
template <class... Args>
void GetNewItem(Args&&... args) { FactoryBaseT::GetNewItem(m_a, std::forward<Args>(args)...); }
double m_a;
}
template<class BaseT>
class MixInB : public BaseT
{
public:
template <class... Args>
void MixInB(double a, Args&&... args) { m_b(b), Base(std::forward<Args>(args)...); }
double m_b;
}
template<class FactoryBaseT>
class FactoryMixInB : public FactoryBaseT
{
public:
template <class... Args>
void GetNewItem(Args&&... args) { FactoryBaseT::GetNewItem(m_b, std::forward<Args>(args)...); }
double m_b;
}
这适用于单个mixin,但遗憾的是无法扩展。
例如,如果我们有工厂
typedef FactoryMixInB<FactoryMixInA<BaseFactory> > FinalFactory
typedef MixInB<MixInA<Base> > FinalItem
然后FinalFactory::GetNewItem(Args&&... args)
扩展为GetNewItem(m_a, m_b, ...)
但构造函数扩展为FinalItem::FinalItem(m_b, m_a, ...)
问题是构造函数构建为Base
- &gt; MixInA
- &gt; MixInB
工厂开始FactoryMixInB
- &gt; FactoryMixInA
- &gt; BaseFactory
这个问题的解决方案是什么?
我正在考虑通过写
来改变工厂的方向template<class FactoryBaseT>
class FactoryMixInB : public FactoryBaseT
{
public:
template <class... Args,class... Args2>
void GetNewItem(Args&&... args)
{
Args2&&... base_args = FactoryBaseT::GetAdditionalConstructorArgs();
Args&&... new_args = GetAdditionalConstructorArgs();
GetNewItem(std::forward<Args>(new_args)..., std::forward<Args2>(base_args)...);
}
template <class... Args>
Args&&... GetAdditionalConstructorArgs() { return m_b; }
double m_b;
}
但这不起作用,因为它需要返回参数包,我认为这不可能。
还有其他答案吗?包装可以包裹在例如一个元组?这有设计模式吗?
答案 0 :(得分:2)
要返回/存储可变参数包的内容,最简单的方法是使用元组:
template<typename... ARGS>
std::tuple<ARGS...> GetAdditionalConstructorArgs() { return std::mke_tuple( pack... ); }
...
auto new_args = GetAdditionalConstructorArgs();
请注意,我已从返回中删除了rvalue-reference。 永远不会作为右值引用返回,只是按值返回 。
稍后如果您需要将作为元组存储的元组作为可变参数包传递,则需要递归地提取元组的内容。有一个叫做索引技巧的成语,它提取元组元素,递归地将它们扩展为可变参数包:
template<std::size_t... INDICES>
struct indices{};
template<typename F , typename... ARGS , std::size_t... INDICES>
void tuple_call( F function , std::tuple<ARGS...>&& tuple , indices<INDICES...> )
{
function( std::forward<typename std::tuple_element<INDICES, std::tuple<ARGS...>>::type>( std::get<INDICES>( tuple ) )... );
}
template<typename F , typename... ARGS>
void tuple_call( F function , std::tuple<ARGS...>&& tuple )
{
tuple_call( function , std::forward<std::tuple<ARGS...>>( tuple ) , generate_indices<sizeof...(ARGS)>{} );
}
最后,generate_indices
类型是一个元函数,可生成indices
模板实例,其中包含从0
到N-1
的数字,其中N
是大小(元组的长度。
以下是tuple_call
的使用示例:
tuple_call( [&]( int a , bool b , char c ) { std::cout << a; } ,
std::make_tuple( 1 , true , 'a' )
);
有关索引技巧的更多信息,我建议您:http://loungecpp.wikidot.com/tips-and-tricks%3aindices