Reputation: 436
I have a templated struct that has a method that (along with other parameters) accepts those templated parameters.
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;
};
I want to make all the templated arguments optional. So that it looks like this:
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!
As far as I know there is not straight forward way? But maybe someone know a workaround or a trick.
Ideally, I'd like to provide my own defaults. Maybe like this:
enum class SomeEnum { Val1, Val2 };
Observer<float, SomeEnum, 0.f, SomeEnum::Val1> observer;
observer.subscribe("id1", 3.14);
Here is LIVE EXAMPLE.
Upvotes: 2
Views: 346
Reputation: 304182
Boost.Mp11 for the win:
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());
}
The assumes that value initialization of the trailing arguments is fine. If it's not, you'll have to figure out what to do with Us
.
Works nicer if you actually make the optional more explicit:
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;
};
Upvotes: 1
Reputation: 26194
In C++17 you can simply do something like:
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...`
}
}
};
Here I am simply picking them from Observer::defaults
, but feel free to compute them however you want.
For C++14 and below, you will need to emulate the if constexpr
. See e.g. Constexpr if alternative for alternatives.
Upvotes: 2