【问题标题】:Having trouble with parameter pack expansion参数包扩展有问题
【发布时间】:2018-01-25 17:57:44
【问题描述】:

我正在处理一个类模板,其中模板本身不是可变参数类型,但是类的构造函数是。我正在尝试获取参数包的所有值并将它们存储到一个向量中,但我似乎无法编译代码,我不断收到编译器错误消息,指出必须在此上下文中扩展参数包,并且我不确定正确的语法是什么。这是我的课:

template<class T>
class TableRow {
private:
    std::string id_;
    std::vector<T> values_;

public:
    template<class T, class... Params>
    TableRow( const std::string& id, T firstVal, Params... valuePack ) :
    id_(id) {
        values.push_back( firstVal );
        for ( auto t : (valuePack...) ) {  // Compiler error here
             values_.push_back( t ); 
        }
    }

    // ... other methods
};

除了让它正确编译之外,我唯一关心的其他问题是有没有办法确保所有Params 都是T 类型?

换句话说,这就是我在实例化这个类时想要实现的目标

TableRow<int> trInt1( "Row1", 1, 2, 3, 4, 5 );
TableRow<int> trInt2( "Row2", 6, 7, 8, 9, 10 );

TableRow<float> trFloat1( "Row1", 2.2f, 3.3f, 4.4f );
TableRow<float> trFloat2( "Row1", 4.5f, 7.9f );

// In the above examples the first two rows are of the same length
// meaning their vector sizes are equal in length therefor they are
// compatible to fit inside of single table. The table is
// a class template that takes type <T> the same type as the RowTable<T>.
// The Table<T>'s constructor accepts a TableRow<T>. 

// With the next two examples of the floats they are both indeed table rows
// but they can not fit into the same table since they are of different length

// The following is what I do not want:
TableRow<char>  row( "row1", 'a', 3, 5, 2.4f, someClass ); 
// This is not allowed, all data types from the 2nd parameter on
// must all be of the same type!

编辑

我接受了liliscent 的建议并将我的类模板的声明更改为如下所示:

template<class T>
class TableRow {
private:
    std::string id_;
    std::vector<T> values_;

public:
    template<class... Params>
    TableRow( std::string id, Params&&... valuePack ) :
        id_( id ),
        values_ { std::forward<Params>( valuePack )... }
    {}

    std::string getID() const {
        return id_;
    }

    std::vector<T> getValues() const {
        return values_;
    }

    std::size_t getSize() const {
        return values_.size();
    }
};

现在编译...感谢您的帮助,因为我现在可以继续编写本课程的其余部分。晚些时候;一旦我的两个班级一起工作,如果一切顺利,我会接受他们的回答。

【问题讨论】:

  • std::vector&lt;T&gt; getValues() const 应该是 const std::vector&lt;T&gt;&amp; getValues() const 以避免不必要的复制。

标签: c++ templates variadic-functions


【解决方案1】:

您的编译失败只是一个语法错误,您不能以这种方式使用基于范围的 for 循环。见http://en.cppreference.com/w/cpp/language/range-for

为了解决这个问题,您可以使用std::vectorstd::initializer_list 基于构造函数,它可以自动确保所有值都具有相同的类型。

template<class... Args>
TableRow( const std::string& id, Args&&... valuePack )
    : id_(id)
    , values_{ std::forward<Args>(valuePack)... }
{}

而且我认为如果你想进一步修复TableRow 中的元素数量,你应该使用std::array。然后你可以有另一个模板参数int N 在编译时检查某些行是否可以放入表中。

【讨论】:

  • 啊,这就是我所缺少的; vector's initialize_list. Yeah I could use array, but I'm preferring to use vector`...
  • 但是,它并不能解决在剥离参数包中的元素之前使用第一个 T 的问题,除非我完全删除它并只使用完整包。
  • 您想在将第一个T 插入向量之前使用它吗?
  • 否;我想先将它推入向量,然后再推入参数包。
  • 如果你想从包中推导出T,你可以使用std::common_type_t&lt;Args...&gt;
【解决方案2】:

语法错误的修复:

template<class T, class... Params>
TableRow( const std::string& id, T firstVal, Params... valuePack ) :
id_(id) {
    values.push_back( firstVal );
    for ( auto t : { valuePack...} ) { // or { static_cast<T>(valuePack) ...}
         values_.push_back( t ); 
    }
}

我建议直接拿vector

TableRow(const std::string& id, std::vector<T> values) :
id_(id), values(std::move(values)) {}

用法有点不同:

TableRow<int> trInt1( "Row1", { 1, 2, 3, 4, 5 });
TableRow<int> trInt2( "Row2", { 6, 7, 8, 9, 10 });

TableRow<float> trFloat1( "Row1", { 2.2f, 3.3f, 4.4f });
TableRow<float> trFloat2( "Row1", { 4.5f, 7.9f });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多