Reputation: 3938
I need to convert elements of a std::vector to types based on a template parameter and call a function with these parameters. In pseudocode:
template <typename T...>
void foo(std::vector<std::string> v) {
if (v.size() != sizeof...(T))
throw std::runtime_error("Bad");
bar(convert<T0>(v[0]), convert<T1>(v[1]), ..., convert<Tn>(v[n]));
}
My problem is how to obtain the element indices from the parameter pack, I think there will be some kind of a trick using fold expressions, but I can't figure it out.
Upvotes: 3
Views: 236
Reputation: 26282
If you know that the number of elements in a vector is equal to the parameter pack size, you can solve this problem by adding one level of indirection:
template<typename... T, std::size_t... is>
void foo_impl(const std::vector<std::string>& v, std::index_sequence<is...>) {
bar(convert<T>(v[is])...);
}
template<typename... T>
void foo(const std::vector<std::string>& v) {
assert(v.size() == sizeof...(T));
foo_impl<T...>(v, std::index_sequence_for<T...>{});
}
The idea here is to expand two packs, Ts...
and is...
, which have equal sizes, simultaneously.
C++20 solution:
template<typename... T>
void foo(const std::vector<std::string>& v) {
assert(v.size() == sizeof...(T));
[&v]<std::size_t... is>(std::index_sequence<is...>) {
bar(convert<T>(v[is])...);
}(std::index_sequence_for<T...>{});
}
Upvotes: 6
Reputation: 5680
You could solve this by using an std::integer_sequence
to access the elements of the vector.
namespace detail
{
template <typename...T, size_t...I>
void foo(std::vector<std::string>& v, std::index_sequence<I...>) {
bar(convert<T>(v[I])...);
}
}
template <typename...T>
void foo(std::vector<std::string>& v) {
if (v.size() != sizeof...(T))
throw std::runtime_error("Bad");
detail::foo<T...>(v, std::index_sequence_for<T...>{});
}
On Godbolt: Link
Upvotes: 5