【问题标题】:Combine class template default parameters and variadic parameters结合类模板默认参数和可变参数
【发布时间】:2018-02-23 16:37:27
【问题描述】:

我正在设计一个 Host 类,它使用固定数量的 Policies 类,大约 3 或 4 个。

因为对于设计中的每个Policy,总会有一个琐碎的实现,因此最好将模板参数默认为琐碎类型,以方便其客户使用Host 类。

class IdiotBenchPolicy {};
class IdiotLoggerPolicy {};
// ...

template <typename BenchmarkPolicy = IdiotBenchPolicy, 
          typename LoggerPolicy = IdiotLoggerPolicy>
class Host
{
     BenchmarkPolicy m_bench;
     IdiotLoggerPolicy m_logger;
};

这允许实例化Host,而无需指定一长串模板参数。

这很好,直到Host 类还必须采用可变数量的算术类型。拆分问题时,忘记Policies,我可以使用可变参数模板参数:

template <class... Args>
class Host
{
    template <class ...Var_Args>
    using are_arithmetic = typename std::conjunction<std::is_arithmetic<Var_Args>...>::type;

    static_assert(are_arithmetic<Args...>::value, "Args are not all arithmetic type");
    std::tuple<Args...> m_args;
};

请注意,即使Host 在内部使用元组,除非必要,否则最好不要在类客户端上强制执行它。

我现在的问题是将这两种行为结合起来。如果“默认”足够,如何实例化Host 类而无需指定Policies。我不知道如何用 C++ 模板语法来表达这一点,但我的直觉告诉我可以通过 SFINAE 和 std::enable_if 来实现,但是我很难理解如何。

我希望能够写的是:

Host<int, int, float> h; //Using both default policies
Host<SmarterBenchPolicy, float, double> h2; //Using SmarterBenchPolicy, IdiotLoggerPolicy and two arithmetic types
Host<SmarterBenchPolicy>; //Using SmarterBenchPolicy, IdiotLoggerPolicy and no arithmetic type

如何实现这样一个Host 类,可以使用类似于上面指定的实例化来构造?

【问题讨论】:

  • 一种解决方法可能是期望TypeListHolder&lt;Args...&gt;(带有template&lt;class...&gt; class TypeListHolder)而不是Args...,并通过type_list&lt;int, float /*...*/&gt;(带有template&lt;class...&gt; struct type_list {};)而不是int, float /*...*/
  • 另外,您可以让特征类告诉您一个类是否是合适的策略,并根据第一个模板参数是“合适的策略类”还是用于可变参数包的看似任意类型进行专门化。
  • @Caninonos 我考虑过你的第二个解决方案,但据我所知,这意味着Host 仅将Args... 作为模板参数,然后尝试将每个 Arg 解压缩到使用策略特征的策略类型之一。我只想写一次Host 的实现,所以这意味着从专业中调用主模板版本?
  • 嗯,基本上,你可以这样做:ideone.com/FokpOQ 并利用继承来避免重写 Host 的实现。
  • @Caninonos 这里继承是公开的,但我认为可以私下继承并在Host 中定义bench 方法,然后从内部调用tell_me_what_you_chose?是否可以将组合与Host_aux 一起使用?

标签: c++ templates variadic-templates


【解决方案1】:

我认为如果将这些具有默认值的参数放在参数列表的 and 中会更好。可变参数可以打包成std::tuple:

template <class ArgsPack,
          typename BenchmarkPolicy = IdiotBenchPolicy,
          typename LoggerPolicy = IdiotLoggerPolicy,
          std::enable_if_t<detail::is_tuple<ArgsPack>::value, int> = 0
          >
struct Host
{
    BenchmarkPolicy     bench;
    LoggerPolicy        logger;
    ArgsPack            args;

    void show_all() {
        detail::tuple_foreach([](const auto &e) {std::cout << e << "\n";}, args);
    }
};

Host<std::tuple<int, int, float>, SmartBenchPolicy> h;

【讨论】:

    【解决方案2】:

    这是一种方法。它必须扩展到两个策略参数,除了一个。

    #include <iostream>
    #include <type_traits>
    #include <tuple>
    
    struct BenchPolicyBase {
    
    };
    
    struct BenchPolicy1 : BenchPolicyBase {
    
    };
    
    template <class enabler, class... Args>
    class HostClass
    {
        //Use default policy
        public:
        HostClass() { std::cout << "default" << std::endl; }
        template <class ...Var_Args>
        using are_arithmetic = typename std::conjunction<std::is_arithmetic<Var_Args>...>::type;
    
        static_assert(are_arithmetic<Args...>::value, "Args are not all arithmetic type");
        std::tuple<Args...> m_args;
    
        BenchPolicyBase m_bench;
    };
    
    template <typename T, typename... Rest>
    using Host = HostClass<void, T, Rest...>;
    
    template <class BenchPolicy, class... Args>
    class HostClass<std::enable_if_t<std::is_base_of<BenchPolicyBase, BenchPolicy>::value>, BenchPolicy, Args...>
    {
        //Use BenchPolicy
        public:
        HostClass() { std::cout << "Bench" << std::endl; }
        template <class ...Var_Args>
        using are_arithmetic = typename std::conjunction<std::is_arithmetic<Var_Args>...>::type;
    
        static_assert(are_arithmetic<Args...>::value, "Args are not all arithmetic type");
        std::tuple<Args...> m_args;
    
        BenchPolicy m_bench;
    };
    
    int main() {
        Host<int, long> a;
        Host<BenchPolicy1, int, long> b;
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-06
      • 1970-01-01
      • 2016-11-09
      • 2019-09-12
      • 1970-01-01
      • 2021-12-27
      • 1970-01-01
      相关资源
      最近更新 更多