Using a template struct such as many
below, it's possible to return a fixed set of possibly unmovable objects, and receive them using the c++17 structured binding (auto [a, b, c] = f();
declares the variables a
, b
and c
and assigns their value from f
returning for example a struct or tuple).
template<typename T1,typename T2,typename T3>
struct many {
T1 a;
T2 b;
T3 c;
};
// guide:
template<class T1, class T2, class T3>
many(T1, T2, T3) -> many<T1, T2, T3>;
auto f(){ return many{string(),5.7, unmovable()}; };
int main(){
auto [x,y,z] = f();
}
As explained in these two questions and answers (Do std::tuple and std::pair support aggregate initialization?
and especially the accepted answer by ecatmur, also Multiple return values (structured bindings) with unmovable types and guaranteed RVO in C++17), std::tuple
does not support aggregate initialization. That means that it can not be used to hold and return unmovable types. But a simple struct like many
can do this, which leads to the question:
Is it possible to create a variadic version of many
which works with any number of arguments?
Update: in a templated version of many
, will the following guide syntax be allowed?
template<typename Args...>
many(Args...) -> many<Args...>;
In C++17 aggregate initialization will be able to initialize public base classes. So you can use inheritance + pack expansion to build such class. To make it work with structured bindings, you will have to expose tuple interface: specialize std::tuple_size
and std::tuple_element
and provide get
function for your class:
//Headers used by "many" class implementation
#include <utility>
#include <tuple>
namespace rw {
namespace detail {
template <size_t index, typename T>
struct many_holder
{ T value; };
template <typename idx_seq, typename... Types>
struct many_impl;
template <size_t... Indices, typename... Types>
struct many_impl<std::index_sequence<Indices...>, Types...>: many_holder<Indices, Types>...
{};
}
template <typename... Types>
struct many: detail::many_impl<typename std::make_index_sequence<sizeof...(Types)>, Types...>
{};
template<size_t N, typename... Types>
auto get(const rw::many<Types...>& data) -> const std::tuple_element_t<N, rw::many<Types...>>&
{
const rw::detail::many_holder<N, std::tuple_element_t<N, rw::many<Types...>>>& holder = data;
return holder.value;
}
}
namespace std {
template <typename... Types>
struct tuple_size<rw::many<Types...>> : std::integral_constant<std::size_t, sizeof...(Types)>
{};
template< std::size_t N, class... Types >
struct tuple_element<N, rw::many<Types...> >
{ using type = typename tuple_element<N, std::tuple<Types...>>::type; };
}
//Headers used for testing
#include <iostream>
#include <string>
int main()
{
rw::many<int, std::string, int> x = {42, "Hello", 11};
std::cout << std::tuple_size<decltype(x)>() << '\n' << rw::get<1>(x);
}
Demo (right now works only in clang 3.9): http://melpon.org/wandbox/permlink/9NBqkcbOuURFvypt
Notes:
nth_type
, you can use to inplement tuple_element
directly and not defer it to tuple_element<tuple>
implementation.get<many>
should be either a member function of many
or be placed in associated namespace for structured bindings to work. You should not overload std::get
(It would be UB anyway).get
for non-const references and r-value references as excercise for the reader. template<typename... Types> many(Types...) -> many<Types...>;
should work.There was a discussion about this on std-proposals just the other day.
We don't have final wording yet, or for that matter a compiler (that I'm aware of) that supports deduction guides, but according to Richard Smith the following deduction guide should work (precis'd):
template<class A, class B>
struct Agg
{
A a;
B b;
};
template<class A, class B>
Agg(A a, B b) -> Agg<A, B>;
Agg agg{1, 2.0}; // deduced to Agg<int, double>
So yes, a variadic deduction guide for an aggregate should also work and will work with aggregate initialization syntax. It won't work without a deduction guide, as without a deduction guide the compiler needs a constructor.
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