【问题标题】:Adding a factory hierarchy to C++ Mixins将工厂层次结构添加到 C++ Mixins
【发布时间】:2014-06-01 09:10:38
【问题描述】:

我正在尝试使用 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&amp;&amp;... args) 扩展为GetNewItem(m_a, m_b, ...) 但构造函数扩展为FinalItem::FinalItem(m_b, m_a, ...)

问题是构造函数被构建了Base -> MixInA -> MixInB

工厂去了FactoryMixInB -> FactoryMixInA -> 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;
}

但这不起作用,因为它需要返回一个参数包,我认为这是不可能的。

还有其他答案吗?可以将包装包裹到例如一个元组?有这方面的设计模式吗?

【问题讨论】:

  • 使用元组和索引技巧返回一个可变参数包并再次将其作为一个包传递

标签: c++ mixins


【解决方案1】:

要返回/存储可变参数包的内容,最简单的方法是使用元组:

template<typename... ARGS>
std::tuple<ARGS...> GetAdditionalConstructorArgs() { return std::mke_tuple( pack... ); }

...

auto new_args = GetAdditionalConstructorArgs();

请注意,我已从返回中删除了右值引用从不作为右值引用返回,只按值返回

稍后,如果您需要将存储为元组的包再次作为可变参数包传递,则需要递归地提取元组的内容。有一个成语称为索引技巧,它提取元组元素递归地将它们扩展为可变参数包:

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 模板实例,其编号从0N-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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-06
    • 2020-03-14
    • 1970-01-01
    • 2018-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多