аргументы шаблона переменной со значениями по умолчанию - PullRequest
2 голосов
/ 23 апреля 2019

У меня есть шаблонная структура, в которой есть метод, который (наряду с другими параметрами) принимает эти шаблонные параметры.

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);

Вот ПРИМЕР ЖИВОГО .

Ответы [ 2 ]

2 голосов
/ 23 апреля 2019

В 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, если альтернатива для альтернатив.

1 голос
/ 23 апреля 2019

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