使用可变模板进行统一初始化

uniform initialization with variadic templates

本文关键字:初始化      更新时间:2023-10-16

我有一个POD ChParam,它是可变模板函数set中的一个参数。我想传递给函数参数(构造函数参数)在花括号p.set({ Param::D, 1000.f }, { Param::p, 2000.f })。并且认为将隐式调用构造函数并创建ChParam对象。但这是不可能的,我应该显式地创建一个对象a.set(ChParam{ Param::D, 1000.f }, ChParam{ Param::p, 2000.f });

是否有可能使用p.set({ Param::D, 1000.f }, { Param::p, 2000.f })的变体?

#include <iostream>
using namespace std;
using Float = float;
enum class Param : size_t
{
    D = 0,
    p
};
struct ChParam
{
    Param tag_;
    Float value_;
};
class PipeCalcParams
{
private:
    Float D_, p_;
public:
    PipeCalcParams() : D_(0), p_(0) {}
    PipeCalcParams& set_D(Float D) { D_ = D; return *this; }
    PipeCalcParams& set_p(Float p) { p_ = p; return *this; }

    template <typename... Args>
    PipeCalcParams& set(const ChParam& p, Args&&... args) {
        set(p);
        return set(args...);
    }
    PipeCalcParams& set(const ChParam& p)
    {
        switch (p.tag_)
        {
        case Param::D:
            set_D(p.value_);
            break;
        case Param::p:
            set_p(p.value_);
            break;
        }
        return *this;
    }
};
int main() {
    PipeCalcParams a;
    a.set(ChParam{ Param::D, 1000.f }, ChParam{ Param::p, 2000.f });//OK
    PipeCalcParams p;
    p.set({ Param::D, 1000.f }, { Param::p, 2000.f });//error: no matching function for call to 'PipeCalcParams::set(<brace-enclosed initializer list>, <brace-enclosed initializer list>)' p.set({ Param::D, 1000.f }, { Param::p, 2000.f });
    return 0;
}

不能直接使用

{ Param::D, 1000.f }

在需要推导时作为函数参数。这样做的原因是大括号初始化列表没有类型。因为它没有类型,所以编译器不能推导出类型。你必须帮助它前进。你可以像之前那样指定类型,比如

ChParam{ Param:D, 1000.f }

或者您可以指定期望的对象类型。如果你想要相同类型的变量数,那么std::intializer_list就可以了。它允许编译器从单个带括号的初始化列表中构造元素。使用它,您的代码将看起来像

PipeCalcParams& set(std::initializer_list<ChParam> args)

调用时使用

p.set({{ Param::D, 1000.f }, { Param::p, 2000.f }})

请注意使用的额外花括号。最外层的集合声明std::intializer_list,每个内部的集合声明列表中的每个ChParam