Suppose I have a wrapper:
template<typename T>
struct Outer {
T inner;
...
};
, and I want to create an Outer
wrapping an Inner
, like so:
Outer<Inner> wrapper(Inner(...)); // Inner object is a temporary
Is it possible to declare Outer
/Inner
such that creating an Outer
object from a temporary Inner
involves the construction of only a single Inner
object? I tried declaring the move constructor for Inner
, and having Outer
take an rvalue reference to Inner
, and even explicitly calling std::move
on the temporary, but still, 2 copies of Inner
are created:
#include <stdio.h>
#include <utility>
template<typename T>
struct Outer {
T inner;
Outer(T&& inner) : inner(inner) {}
};
struct Inner {
int x;
int y;
Inner(const int x, const int y) : x(x), y(y) { printf("ctor\n"); }
Inner(const Inner& rhs) : x(rhs.x), y(rhs.y) { printf("copy ctor\n"); }
Inner(Inner&& rhs) : x(std::exchange(rhs.x, 0)), y(std::exchange(rhs.y, 0)) {
printf("move ctor\n");
}
Inner& operator=(const Inner& rhs) {
printf("assign\n");
return *this = Inner(rhs);
}
Inner& operator=(Inner&& rhs) {
printf("move assign\n");
std::swap(x, rhs.x);
std::swap(y, rhs.y);
return *this;
}
~Inner() { printf("dtor\n"); }
};
int main() {
Outer<Inner> wrapper(Inner(123, 234));
// SAME: Outer<Inner> wrapper(std::move(Inner(123, 234)));
return 0;
}
Output:
ctor <-- The temporary
copy ctor <-- Yet another instance, from the temporary
dtor
dtor
As shown above, the creation of an Outer
instance creates 2 Inners
. This seems strange as I thought the temporary can be elided, or at least, invoke the move constructor. Is it possible to instantiate Outer
with a single Inner
construction?
I guess you are looking for this:
#include <stdio.h>
#include <utility>
template <typename T> struct Outer {
T inner;
// Outer(T &&inner) : inner(std::move(inner)) {}
template <class... Args> Outer(Args &&...args) :inner(args...) {}
};
struct Inner {
int x;
int y;
Inner(const int x, const int y) : x(x), y(y) { printf("ctor\n"); }
Inner(const Inner &rhs) : x(rhs.x), y(rhs.y) { printf("copy ctor\n"); }
Inner(Inner &&rhs)
: x(std::exchange(rhs.x, 0)), y(std::exchange(rhs.y, 0)) {
printf("move ctor\n");
}
Inner &operator=(const Inner &rhs) {
printf("assign\n");
return *this = Inner(rhs);
}
Inner &operator=(Inner &&rhs) {
printf("move assign\n");
std::swap(x, rhs.x);
std::swap(y, rhs.y);
return *this;
}
~Inner() { printf("dtor\n"); }
};
int main() {
Outer<Inner> wrapper(123, 234);
// SAME: Outer<Inner> wrapper(std::move(Inner(123, 234)));
return 0;
}