Reputation: 7925
I working on a class template where the template itself is not of a variadic type, however the constructor of the class is. I'm trying to take all the values of the parameter pack and store them into a vector, but I can not seem to get the code to compile, I keep getting compiler error messages that the parameter pack must be expanded in this context, and I'm not sure what the proper syntax is. Here is my class:
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
};
Other than getting this to compile correctly the only other concern that I have is that is there a way to ensure that all Params
are of type T
?
Another words this is what I'm trying to achieve when instantiating this class
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!
EDIT
I took liliscent
advise and changed my class template's declaration to look like this:
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();
}
};
And this now compiles... Thank you for your help as I can now move on with writing the rest of this class. At a later time; once I have my two classes working together if all goes well, I'll accept their answer.
Upvotes: 2
Views: 1862
Reputation: 218278
The fix of your syntax error:
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 );
}
}
I suggest to take vector
directly:
TableRow(const std::string& id, std::vector<T> values) :
id_(id), values(std::move(values)) {}
With usage a little different:
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 });
Upvotes: 0
Reputation: 16434
Your compile failure is simply a syntax error, you can't use range-based for loop in this way. See http://en.cppreference.com/w/cpp/language/range-for.
For solving the problem, you can use std::vector
's std::initializer_list
based constructor, which ensures all values have the same type automatically.
template<class... Args>
TableRow( const std::string& id, Args&&... valuePack )
: id_(id)
, values_{ std::forward<Args>(valuePack)... }
{}
And I think if you want to further fix the number of elements in your TableRow
, you should use std::array
. Then you can have another template parameter int N
to check at compile time whether certain rows can be put into a table.
Upvotes: 2