如何在初始化时使用可变参数来在初始化时包括不同数量的对象?

问题描述

这是上一个问题(Link)的扩展

我需要根据提供的“定义”和不同的ctor参数包括不同数量的对象。第一个参数是对象从零到(NUMBER-1)的“索引”,其他参数是可选的。

到目前为止,当仅显示单个“索引”参数时,我还没有问题,但是我仍在努力添加可选参数Args... args

这就是我要尝试的方法。假设我们要实例化以下两个类

class Output
{
public:
    explicit Output(uint32_t idx) : m_idx(idx) { printf("ctor: %u\n",m_idx); };
private:
    uint32_t m_idx = -1;
};

class Input
{
public:
    explicit Input(uint32_t idx,std::string name) : m_idx(idx),m_name(name) { printf("ctor: %u [%s]\n",m_idx,m_name.data()); };
private:
    uint32_t m_idx = -1;
    std::string m_name;
};

有2个可通过顺序索引实例化的模板

template<typename T,typename... Args,typename TInts,TInts... I>
constexpr auto MakeArrayHelper(Args... args,std::integer_sequence<TInts,I...>)
{
    return std::array<T,sizeof...(I)>{ (I)...,std::forward<Args>(args)... };
}

template <typename T,size_t Count,typename BaseType = uint32_t>
constexpr auto MakeArray(Args... args)
{
    return MakeArrayHelper<T>((args)...,std::make_integer_sequence<BaseType,Count>());
}

我想实例化这样的类

    auto outputs = MakeArray<Output,5>();
    auto inputs = MakeArray<Input,3>(std::string("Analog"));

    expanded into:
std::array<Output,5> = { Output{0},Output{1},Output{2},Output{3},Output{4} };
std::array<Input,3> = { Input{0,"Analog"},Input{1,Input{2,"Analog"} };

这给我带来了一个编译错误Could not deduce template argument for 'TInts'

您能帮助我了解我做错了什么吗? 谢谢。

解决方法

如果没有完整的示例,很难给出完整的答案,但是...我在MakeArrayHelper()中看到了一些问题

首先,参数的可变参数包必须位于最后一个位置,否则推导将失败。

所以,而不是

template<typename T,typename... Args,typename TInts,TInts... I>
constexpr auto MakeArrayHelper(Args... args,std::integer_sequence<TInts,I...>)

您可以尝试

template<typename T,TInts... I,typename... Args>
constexpr auto MakeArrayHelper(std::integer_sequence<TInts,I...>,Args ... args)

第二:如果要使用转发,则args参数必须是转发引用

template<typename T,Args && ... args)
// .....................................................................^^

第三:在函数内部,您声明了std::array<T,sizeof...(TInts)>,但您使用了它来初始化

{ (I)...,std::forward<Args>(args)... };

一系列sizeof...(TInts)和一些args...

我不明白您想要获得什么,但这显然是错误的。

-编辑--

或者也许我理解您想要什么...如果我理解正确,那么您想要的就是(警告:未经测试的代码)

template <typename T,typename ... Args>
constexpr auto MakeArrayHelper (std::integer_sequence<TInts,Args const & ... args)
{
    return std::array<T,sizeof...(I)>{ T{I,args...} ... };
}

template <typename T,std::size_t Count,typename BaseType = std::uint32_t,typename ... args>
constexpr auto MakeArray (Args const & ... args)
 {
    return MakeArrayHelper<T>(std::make_integer_sequence<BaseType,Count>(),args...);
 }

避免在args...中转发MakeArrayHelper(),因为您不能(毫无风险)多次转发同一变量。