Reputation: 562
I'm trying to accomplish something similar to Eigen
advanced initialization for my container class.
i.e. in main
, I want to fill an object of type DynamicArray
as follows:
main.cpp
// Create 3 x 3 Dynamic array and fill with 0's
DynamicArray da(3, 3, 0);
da << 1, 2, 3,
4, 5, 6,
7, 8, 9;
The method I've used to try to accomplish this is:
DynamicArray.hpp
template <typename T>
class DynamicArray {
// ...
public:
// ...
template <typename... Args,
typename = typename std::enable_if<ArgPackSameTruth<
std::is_convertible<Args, T>...>::value,
T>::type
> void operator<<(Args... x) {
typename std::vector<T> arg_vect{std::forward<Args>(x)...};
std::cout << arg_vect.size() << "\n";
// Load contents of arg_vect into *this...
return;
}
}
When I compile main.cpp
, I get a size of 1 for arg_vect
, so only the first parameter is being taken in. How can I make sure all parameters are passed?
Thanks!
Upvotes: 1
Views: 92
Reputation: 1132
operator <<
only takes 1 argument. That's why the size is 1. The numbers after 1 are all unused. If you turn on -Wall
you should get a warning about this.
I can think of 2 solutions.
One would be to simply enclose the numbers in braces {...}
and let operator <<
accept a std::initializer_list<double>
void operator<< (std::initializer_list<double>);
Second solution would be to have Dynamic array overload operator,
and operator<<
Both ,
and <<
would return a DynamicArray so that they could be chained.
DynamicArray& operator<<(double x){
//Add x to the Dynarray
return *this;
}
operator,
Would do the same thing as operator<<
DynamicArray& operator, (double x){
//Add x to the Dynarray
return *this;
}
Here is a baisic example for std::vector
#include <vector>
#include <iostream>
template <typename T>
std::vector<T>&
operator<<(std::vector<T>& x, T y)
{
x.push_back(y);
return x;
}
template <typename T>
std::vector<T>&
operator,(std::vector<T>& x, T y)
{
x.push_back(y);
return x;
}
int main(){
std::vector<int> A;
A << 1,2,3,4,5,6,7,8,9,10;
for(int x : A){
std::cout << x << ",";
}
std::cout << std::endl;
}
Upvotes: 2
Reputation: 56863
The order of operations is different from what you seem to think. If you have:
da << 1, 2, 3;
it is equivalent to (given free operators):
auto tmp1 = operator<<(da,1);
auto tmp2 = operator,(tmp1,2);
auto tmp3 = operator,(tmp2,3);
hence you'd need operators roughly like this:
#include <iostream>
struct DynamicArray
{
};
DynamicArray& operator<<( DynamicArray& da, int i )
{
std::cout << "<<" << i << std::endl;
return da;
}
DynamicArray& operator,( DynamicArray& da, int i )
{
std::cout << "," << i << std::endl;
return da;
}
int main()
{
DynamicArray da;
da << 1, 2, 3,
4, 5, 6,
7, 8, 9;
}
Of course you need to store the values somewhere, etc. Think about a design which allows this and consider adding an intermediate class to hold the values which is returned by operator<<
and which works as both the first input parameter and the return type for operator,
. The destructor of that class can be used to apply the collected intermediate data if needed.
Upvotes: 5