组合类模板默认参数和变异参数

Combine class template default parameters and variadic parameters

本文关键字:参数 变异 默认 组合      更新时间:2023-10-16

我正在设计一个使用固定数量的Policies类的Host类,大约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时,我能够使用variadic模板参数:

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 and 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类是如何实现的?

我认为,如果您将这些参数放在参数列表和默认值的参数会更好。variadic参数可以包装到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;

这是一种方法。它必须将其扩展到两个策略参数。

#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;
}