【问题标题】:C++ Variadic class template designC++ 可变参数类模板设计
【发布时间】:2015-10-05 20:40:04
【问题描述】:

我正在开发一个混合类型的 Config Reader 类,它支持从环境、命令行、文件等读取配置数据。

我有点遵循 std::tuple 类型设计:

template <class... Ts> struct ConfigReader {};

template <class T, class... Ts>
class ConfigReader<T, Ts...> : ConfigReader<Ts...>
{
  public:
    typedef boost::fusion::set<T, Ts...> sequence_type;

    ConfigReader(T t, Ts... ts)
      : ConfigReader<Ts...>(ts...)
      , parameters_(t, ts...)
    {
      this->init();
    }

  private:
    sequence_type parameters_;

    void init()
    {
       boost::fusion::for_each(parameters_, SetFromEnvironment());
       boost::fusion::for_each(parameters_, SetFromCommandLine());
       boost::fusion::for_each(parameters_, SetFromConfigFile());
    }
};

但我意识到我也可以在没有递归继承的情况下定义它

template <class T, class... Ts>
class ConfigReader<T, Ts...>
{
  public:
    typedef boost::fusion::set<T, Ts...> sequence_type;

    ConfigReader(T t, Ts... ts)
      : parameters_(t, ts...)
    {
      this->init();
    }

    template <class Type>
    typename boost::fusion::result_of::value_at_key<Sequence const, Type>::type get()
    {
      return boost::fusion::at_key<Type>(parameters);
    }

  private:
    sequence_type parameters_;

    void init()
    {
       boost::fusion::for_each(parameters_, SetFromEnvironment());
       boost::fusion::for_each(parameters_, SetFromCommandLine());
       boost::fusion::for_each(parameters_, SetFromConfigFile());
    }
};

后一种情况似乎效果更好,因为 init() 只被调用一次,这正是我想要的。但是现在我很困惑这两者之间有什么区别?如果没有递归继承,我会失去一些东西吗?

简化用法是......(忽略参数类型结构)

int main()
{
  ConfigReader<Start, End, Resources> configReader(Start(), End("infinity"), Resources());

  Start startTime = configReader.get<Start>();
}

【问题讨论】:

  • 不清楚你在做什么。特别是,您不只是使用std::tuple 有什么原因吗?什么是init(),它在哪里定义?
  • 我添加了更多信息。但这真的会影响递归继承与非递归继承之间有什么区别的答案吗?

标签: c++ templates c++11 variadic-templates


【解决方案1】:

递归方法没有意义。考虑一个您想要的示例:

ConfigReader<A, B, C> reader(A{}, B{}, C{});

在递归的情况下,你会得到这个层次结构:

ConfigReader<A, B, C> has three readers: A, B, C
    |
    |
    V
ConfigReader<B, C> has two readers: B, C
    |
    |
    V
ConfigReader<C> has one reader: C

您有 6 个读者,而您的意思是只有 3 个!当您执行递归层次结构时,可能的意思是每个实例化只有 一个 阅读器:不是所有的阅读器。那就是:

template <typename T, typename... Ts>
struct ConfigReader : ConfigReader<Ts...> {
    T current;

    ConfigReader(T t, Ts... ts)
    : ConfigReader<Ts...>(ts...)
    , current(t)
    { }
};

但是您使用 boost fusion set 所做的事情直接实现了这一点。不过,对于 C++11,您可能应该坚持使用:

template <typename... T>
struct ConfigReader {
    std::tuple<T...> readers;
};

它应该适合您的目的。

【讨论】:

  • 是的,我从使用元组开始,但我认为支持融合基础设施有很多我需要的实用程序,例如我的 get() 函数,它指定参数类型而不是中使用的索引一个元组。
  • @mike C++14 也添加了std::get&lt;T&gt;()。您还可以相当容易地实现它,并避免 mpl.fusion 带来的所有麻烦。
  • 对 C++14 的添加很有趣,我不知道。我同意 mpl/fusion 有很多包袱。我可能可以实现这些实用程序(或者至少是步履蹒跚,考虑到我的模板经验)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
相关资源
最近更新 更多