I'm trying to design a class which has two vectors of large sequences.
std::vector<double> factory() {
return std::vector<double>{1,2,3}; // it actually generates a large sequence of double
}
struct my_class {
my_class(const std::vector<double>& x, const std::vector<double>& y)
: m_x(x), m_y(y)
{ }
std::vector<double> m_x;
std::vector<double> m_y;
};
int main() {
my_class c(factory(), factory());
my_class c2(factory(), {0.5, 1, 1.5});
}
Well, it works well but it doesn't use the move constructor of vector. So i tried to change the constructor to accept r-value references with perfect forwarding.
struct my_class {
template<typename X, typename Y>
my_class(X&& x, Y&& y
, typename std::enable_if<std::is_convertible<X, std::vector<double> >::value &&
std::is_convertible<Y, std::vector<double> >::value>::type * = 0
)
: m_x(std::forward<X>(x)), m_y(std::forward<Y>(y))
{ }
std::vector<double> m_x;
std::vector<double> m_y;
};
And now i got a problem. When i try to construct an instance with an initializer_list, i got an error like this.
$ g++ -W -Wall -std=gnu++0x a.cpp
a.cpp: In function ‘int main()’:
a.cpp:34:32: error: no matching function for call to ‘my_class::my_class(std::vector<double>, <brace-enclosed initializer list>)’
a.cpp:17:18: note: candidate is: my_class::my_class(const my_class&)
I thought that std::initializer_list<double>
might not be convertible to std::vector<double>
, but it actually is convertible and i got the same error when i tried without the enable_if argument. Am I missing something?
The preferred idiom is to pass by value and then manually move inside the member initializer list:
struct my_class {
my_class(std::vector<double> x, std::vector<double> y)
: m_x(std::move(x)), m_y(std::move(y))
{ }
std::vector<double> m_x;
std::vector<double> m_y;
};
This will work with all possible arguments and be reasonably fast:
x
and then moved into m_x
.x
and then moved again into m_x
.x
will be initialized from that list and then moved into m_x
.The alternative is perfect forwarding, but that makes it harder for the client to know what he may pass in:
struct my_class {
template<typename T, typename U>
my_class(T&& x, U&& y)
: m_x(std::forward<T>(x)), m_y(std::forward<U>(y))
{ }
std::vector<double> m_x;
std::vector<double> m_y;
};
Also, I get a bunch of warnings in g++, so I wouldn't recommend it. Just mentioning it for completeness.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With