I have a builder class that I'd like to store arguments as references for use in subsequent building.
I'd like to pass in a variable number of arguments to my class, infer the template arguments using class template argument deduction, and store those passed arguments as references in a std::tuple.
What's the easiest way to convert from a parameter pack to a std::tuple of references?
I found std::forward_as_tuple which does something similar to what I want, but I don't want a forwarding reference plus it gives a syntax error during initialization of the member tuple.
template <typename... Ts>
struct Builder
{
using ArgsT = decltype(std::forward_as_tuple(Ts{}...));
ArgsT args_;
Builder(Ts&... ts) : args_(ts...) {}
};
int main()
{
struct Foo
{
int a;
double b;
};
Foo foo{};
Builder fooBuilder{foo.a, foo.b};
}
The syntax error is:
error: no matching function for call to
std::tuple<int&&, double&&>::tuple(int&, double&)
If you simply wants reference, use them directly:
template <typename... Ts>
struct Builder
{
using ArgsT = std::tuple<Ts&...>;
ArgsT args_;
Builder(Ts&... ts) : args_(ts...) {}
};
int main()
{
struct Foo
{
int a;
double b;
};
Foo foo{};
Builder fooBuilder{foo.a, foo.b};
}
For your code:
decltype(std::forward_as_tuple(Ts{}...))
resolves in std::tuple<Ts&&...>
.
Ts{}
creates a temporary (and requires your type to be default constructible).
And you cannot bind int&
to int&&
.
You might use decltype(std::forward_as_tuple(std::declval<Ts&>()...))
which resolves in std::tuple<Ts&...>
, but later is simpler and provided solution;-).