【问题标题】:variadic template arguments with default values具有默认值的可变参数模板参数
【发布时间】:2019-09-12 20:21:34
【问题描述】:

我有一个模板化结构,它有一个方法(连同其他参数)接受这些模板化参数。

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

【问题讨论】:

  • 如果没有提供参数,这些参数的值应该是多少?
  • here 所述,这是明确不允许的。我不确定您想如何解决它,因为某些类型不是默认可构造的。
  • @Quentin 我想提供我自己的默认值。更新了描述

标签: c++ parameters c++14 variadic-templates


【解决方案1】:

在 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 替代方案。

【讨论】:

  • 这实际上可以工作。但是您对如何为自定义类型提供默认值有任何想法吗?我更新了描述以显示使用示例
【解决方案2】:

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

【讨论】:

  • 你知道它是否也可以使用自定义默认值吗?我更新了描述
  • s/make_tuple/tie/g
猜你喜欢
  • 1970-01-01
  • 2015-02-04
  • 2016-10-06
  • 2012-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多