Perfect forwarding of a braced initializer to a constructor?
There are similar questions, but none seem to be quite this.
I have a wrapper class that exists to hold an S
. In it's simplest form we have
// A simple class with a two-argument constructor:
struct S {
int x[2];
S(int x, int y) : x{x, y} {}
};
struct WrappedSSimple {
S s;
template <typename... Args>
WrappedSSimple(Args&&... args) : s(std::forward<Args>(args)...) {}
};
which seems to work when I call WrappedSSimple({1,2})
. However, I want to make the c'tor private and have a static factory function. That fails:
struct WrappedS {
S s;
template <typename... Args>
static WrappedS make(Args&&... args) { return WrappedS(std::forward<Args>(args)...); }
private:
template <typename... Args>
WrappedS(Args&&... args) : s(std::forward<Args>(args)...) {}
};
with
<source>:28:14: error: no matching function for call to 'make'
auto w = WrappedS::make({1,2}); // This is not.
^~~~~~~~~~~~~~
<source>:19:21: note: candidate template ignored: substitution failure: deduced incomplete pack <(no value)> for template parameter 'Args'
static WrappedS make(Args&&... args) { return WrappedS(std::forward<Args>(args)...); }
^
https://godbolt.org/z/rsWK94Thq
Is there a way to perfectly forward the braces through the static
make
function?
In your first example WrappedSSimple({1,2})
is calling the move-constructor of WrappedSSimple
with the a temporary constructed via the user-defined constructor as argument.
You cannot replicate this behavior with a factory if the constructor is private, because the temporary object which needs access to the constructor is always created in the context of the caller.
You can also not generally forward untyped braces. The best you can do, if you are fine with restricting the types to be the same for each element of the brace, is to use a std::initializer_list
or a reference to an array as parameter to make
.