我正在设计一个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
类如何实现?
答案 0 :(得分:1)
我认为如果将那些带有默认值的参数放在参数列表中,会更好。可变参数可以打包到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;
答案 1 :(得分:0)
这是一种方法。除了一个之外,它必须扩展到两个Policy参数。
#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;
}