我有一个模板化结构,该结构具有(连同其他参数一起)接受那些模板化参数的方法。
template<class... Types>
struct Observer
{
void subscribe(const std::string& id, Types... args)
{
// store id somehow
data = std::make_tuple(args...);
}
std::tuple<Types...> data;
};
我想使所有模板化参数都是可选的。这样看起来像这样:
Observer<float, int> observer;
observer.subscribe("id1", 3.14, 4);
observer.subscribe("id2", 0.707); // this doesn't work!
observer.subscribe("id3"); // this doesn't work!
据我所知,没有直接的方法吗?但也许有人知道解决方法或技巧。
理想情况下,我想提供自己的默认值。也许像这样:
enum class SomeEnum { Val1, Val2 };
Observer<float, SomeEnum, 0.f, SomeEnum::Val1> observer;
observer.subscribe("id1", 3.14);
这里是LIVE EXAMPLE。
答案 0 :(得分:2)
在C ++ 17中,您可以简单地执行以下操作:
template<class... Types>
struct Observer
{
static constexpr std::tuple<Types...> defaults{42, 24, 99};
template<class... Args>
void subscribe(Args... args)
{
if constexpr (sizeof...(Types) > sizeof...(Args)) {
subscribe(args..., std::get<sizeof...(Args)>(defaults));
} else {
// whatever you need with `args...`
}
}
};
在这里,我只是从Observer::defaults
中挑选它们,但是可以随意计算它们。
对于C ++ 14和更低版本,您将需要模拟if constexpr
。参见例如Constexpr if alternative供选择。
答案 1 :(得分:1)
Boost.Mp11获胜:
template <typename... Ts>
void subscribe(const std::string& id, Ts const&... args)
{
static_assert(sizeof...(Ts) <= sizeof...(Types));
using Rest = mp_drop_c<std::tuple<Types...>, sizeof...(Ts)>;
data = std::tuple_cat(std::make_tuple(args...), Rest());
}
假定尾随参数的值初始化很好。如果不是,则必须弄清楚如何处理Us
。
如果您实际上使可选选项更明确,效果会更好:
template<class... Types>
struct Observer
{
using Data = std::tuple<std::optional<Types>...>;
template <typename... Ts>
void subscribe(const std::string& id, Ts const&... args)
{
static_assert(sizeof...(Ts) <= sizeof...(Types));
using Rest = mp_drop_c<Data, sizeof...(Ts)>;
data = std::tuple_cat(std::make_tuple(args...), Rest());
}
Data data;
};