我将在下面留下我的原始答案,但我会尝试使用可变参数模板来解决您的问题。
使用可变参数函数模板,您无需遍历参数包。您必须改为使用递归函数。
我会使用的东西是这样的:
template <class FirstDomain, class ...Domains>
class Function {
public:
typedef std::tuple<FirstDomain, Domains...> domain_t;
static constexpr size_t dimension = sizeof...(Domains) + 1; //+1 for FirstDomain
private:
std::tuple<std::set<FirstDomain>, std::set<Domains>...> domain;
std::unordered_map<domain_t, double> map;
template <size_t index = 0>
typename std::enable_if<(index < dimension), bool>::type
is_in_domain(const domain_t& t) const {
const auto& set = std::get<index>(domain);
if (set.find(std::get<index>(t)) != set.end()) {
return is_in_domain<index + 1>(t);
}
return false;
}
template <size_t index = 0>
typename std::enable_if<!(index < dimension), bool>::type
is_in_domain(const domain_t& t) const {
return true;
}
public:
Function(std::set<FirstDomain> f, std::set<Domains>... ds) :
: domain(f, ds...) {}
};
诀窍是递归和 SFINAE 的结合。我们需要std::enable_if<>
防止编译器扩展对 的调用std::get<>()
,因为对 get 的索引检查是静态完成的,即使它永远不会执行也会导致编译错误。
如果可以的话,可能的改进领域是通过移动设备来提高施工效率。这将需要完美的转发和其他模板魔术,因为您必须让模板参数推导推导类型,以便引用折叠启动,然后static_assert()
在推导的类型不是预期类型时使用 to 错误(即!(std::is_same<T, std::remove_cv<std::remove_reference<FirstDomain>::type>::type>::value)
,但在可变参数中)形式),然后转发到集合std::forward()
。
(原答案)
在这种情况下,您不想将参数用作模板参数。关于模板参数的各种规则是您不想处理的——特别是所有参数都必须是整数常量表达式。
您只想使用“普通”参数,以便您可以轻松地将它们传递给std::unordered_map
,可以是任何类型,并且可以是运行时定义的:
我会推荐类似的东西:
three_dim_function.set(1, "a", 1.23, 12);
double twelve = three_dim_function.get(1, "a", 1.23);
如果你想让它看起来更好,你可以做一些语法糖:
template <class first_type, class ...addl_types>
class Function {
public:
//...
//left as an exercise for the reader
void set(std::tuple<first_type, addl_types...>, double);
class set_proxy {
friend class Function<first_type, addl_types...>;
std::tuple<first_type, addl_types...> input;
Function<first_type, addl_types...>& parent;
set_proxy(std::tuple<first_type, addl_types...> t, Function<first_type, addl_types...>& f)
: input(t), parent(f) {}
set_proxy(const set_proxy&) = delete;
set_proxy& operator=(const set_proxy&) = delete;
public:
//yes, I know this isn't the right return type, but I'm not sure what's idiomatic
void operator=(double d) {
parent.set(input, d);
}
};
set_proxy set(first_type f, addl_types... addl) {
return set_proxy{std::make_tuple(f, addl...), *this};
}
};
然后,您可以这样做:
Function<int, std::string, double> three_dim_function;
three_dim_function.set(1, "a", 1.23) = 12;