Uniform initialization by tuple
Provide Object
an std::tuple
constructor. You can use std::tie
to assign your members:
template<typename ...Args>
Object(std::tuple<Args...> t) {
std::tie(s, i, d) = t;
}
Now it gets automatically constructed:
std::transform(values.begin(), values.end(), std::back_inserter(objs),
[](auto v) -> Object {
return { v };
});
To reduce the amount of copying you might want to replace auto v
with const auto& v
and make the constructor accept a const std::tuple<Args...>& t
.
Also, it's good practise to access the source container via const
iterator:
std::transform(
values.cbegin(), values.cend()
, std::back_inserter(objs), ...
Here is a non-intrusive version (i.e. not touching Object
) that extracts the number of specified data members. Note that this relies on aggregate initialization.
template <class T, class Src, std::size_t... Is>
constexpr auto createAggregateImpl(const Src& src, std::index_sequence<Is...>) {
return T{std::get<Is>(src)...};
}
template <class T, std::size_t n, class Src>
constexpr auto createAggregate(const Src& src) {
return createAggregateImpl<T>(src, std::make_index_sequence<n>{});
}
You invoke it like this:
std::transform(values.cbegin(), values.cend(), std::back_inserter(objs),
[](const auto& v)->Object { return createAggregate<Object, 3>(v); });
Or, without the wrapping lambda:
std::transform(values.cbegin(), values.cend(), std::back_inserter(objs),
createAggregate<Object, 3, decltype(values)::value_type>);
As @Deduplicator pointed out, the above helper templates implement parts of std::apply
, which can be used instead.
template <class T>
auto aggregateInit()
{
return [](auto&&... args) { return Object{std::forward<decltype(args)>(args)...}; };
}
std::transform(values.cbegin(), values.cend(), std::back_inserter(objs),
[](const auto& v)->Object { return std::apply(aggregateInit<Object>(), v); });
Since C++17, you might use std::make_from_tuple:
std::transform(values.begin(),
values.end(),
std::back_inserter(objs),
[](const auto& t)
{
return std::make_from_tuple<Object>(t);
});
Note: requires appropriated constructor for Object
.