How to sum over an array of variant using a visitor? - c++

I'm trying to find a way to sum over an std::array of std::variant using a visitor. I've gotten this far, but I can't for the life of me figure out how to deduce the type of the visitors without including a void entry at the head of my visitor lambda list.
Does anyone know of a way I can deduce the return type of the lambdas in the visitor so that I don't have to rely on this?
Here's what I've got right now:
#include <array>
#include <iostream>
#include <string_view>
#include <type_traits>
#include <variant>
using namespace std::literals::string_view_literals;
template<typename... Base>
struct Visitor: Base ... {
using Base::operator()...;
};
template<typename... T>
Visitor(T...) -> Visitor<T...>;
// There has to be a better way to deduce Result than what I'm doing...
template<typename... T, typename S, typename... Ss, size_t N, typename Result = typename std::result_of_t<S()>>
constexpr std::enable_if_t<std::is_arithmetic_v<Result>, Result>
summation(const Visitor<S, Ss...> &visitor, const std::array<std::variant<T...>, N> &array) {
Result sum{};
for (const auto &a: array)
sum += std::visit(visitor, a);
return sum;
}
int main() {
constexpr Visitor visitor {
// This first entry should be unnecessary, I would think:
[]() -> double { return 0; },
[](double d) -> double { return d + 3.4; },
[](int i) -> double { return i - 2; },
[](std::string_view s) -> double { return s.size(); }
};
constexpr std::array<std::variant<int, double, std::string_view>, 5> arr{9.0, 9, 3, 5.2, "hello world"sv};
constexpr auto val = summation(visitor, arr);
std::cout << val << '\n';
}
Edit: I'd like the result to be constexpr.
Thanks for any help.

You are being way too explicit with your type infering when auto is there to let the compiler take care of that for you.
Once you are within the scope of the function decltype() and std::declval() make the inference (needed to create the default-initialized target) an easy matter since you can simply mock an actual invocation of the visitor.
template<typename... T, typename S, typename... Ss, size_t N>
constexpr auto summation(const Visitor<S, Ss...> &visitor, const std::array<std::variant<T...>, N> &array) {
using Result = decltype(std::visit(visitor, std::declval<std::variant<T...>>()));
static_assert(std::is_arithmetic_v<Result>);
Result sum{};
for (const auto &a: array)
sum += std::visit(visitor, a);
return sum;
}
I actually much prefer this style since an erroneous invocation will actually yield a sensible error message instead of "function not found". That is unless you will have non-arithmetic versions of accumulate() that you are trying to sfinae against (which would be weird).

A simplification (I hope) of the Frank's decltype()/std::declval() solution.
Using decltype()/std::declval(), you don't need to know S, Ss... and T...; you simply need a template type V for visitor and a template type for array.
You can also avoid the static_assert(), if you prefer, re-enabling SFINAE simply writing
template <typename V, typename A,
typename R = decltype(std::visit(std::declval<V>(), std::declval<A>().at(0)))>
constexpr std::enable_if_t<std::is_arithmetic_v<R>, R>
summation(V const & visitor, A const &array)
{
R sum{};
for (const auto &a: array)
sum += std::visit(visitor, a);
return sum;
}

Related

Replace N-th element of a std::tuple

What is the shortest / best way to replace the n-th element of a tuple with a value (which may or may not have a different type)? Solutions including c++20 are fine.
[EDIT: I would prefer something not requiring other libraries, but I'm still interested what solutions are possible with e.g. boost].
I.e.:
#include <cassert>
#include <tuple>
template<std::size_t N, ... >
auto replace_tuple_element( ... ) // <- Looking for a suitable implementation
struct Foo {
int value;
};
int main()
{
auto t1 = std::tuple{ 0, 1, 2, 3 };
auto t2 = replace_tuple_element<2>( t1, Foo{10} );
assert( std::get<0>(t2) == std::get<0>(t1));
assert( std::get<1>(t2) == std::get<1>(t1));
assert( std::get<2>(t2).value == 10);
assert( std::get<3>(t2) == std::get<3>(t1));
}
Note: Just replacing the n-th type in a typelist has e.g. be discussed here: How do I replace a tuple element at compile time?.
But I also want to replace the value and hope that there are simpler/more elegant solutions now in c++20 than back when that question was asked.
One solution I found for c++20 is this:
#include <cassert>
#include <tuple>
#include <type_traits>
template<std::size_t N, class TupleT, class NewT>
constexpr auto replace_tuple_element( const TupleT& t, const NewT& n )
{
constexpr auto tail_size = std::tuple_size<TupleT>::value - N - 1;
return [&]<std::size_t... I_head, std::size_t... I_tail>
( std::index_sequence<I_head...>, std::index_sequence<I_tail...> )
{
return std::tuple{
std::get<I_head>( t )...,
n,
std::get<I_tail + N + 1>( t )...
};
}(
std::make_index_sequence<N>{},
std::make_index_sequence<tail_size>{}
);
}
struct Foo {
int value;
};
int main()
{
auto t1 = std::tuple{ 0, 1, 2, 3 };
auto t2 = replace_tuple_element<2>( t1, Foo{10} );
assert( std::get<0>(t2) == std::get<0>(t1));
assert( std::get<1>(t2) == std::get<1>(t1));
assert( std::get<2>(t2).value == 10);
assert( std::get<3>(t2) == std::get<3>(t1));
}
What I like about the solution is that it is a single, self containied function. I wonder if there is something even shorter and/or more readable though.
Possible solution:
template<std::size_t i>
using index = std::integral_constant<std::size_t, i>;
template<std::size_t N, class Tuple, typename S>
auto replace_tuple_element(Tuple&& tuple, S&& s) {
auto get_element = [&tuple, &s]<std::size_t i>(Index<i>) {
if constexpr (i == N)
return std::forward<S>(s);
else
return std::get<i>(std::forward<Tuple>(tuple));
};
using T = std::remove_reference_t<Tuple>;
return [&get_element]<std::size_t... is>(std::index_sequence<is...>) {
return std::make_tuple(get_element(index<is>{})...);
}(std::make_index_sequence<std::tuple_size_v<T>>{});
}
Note this decays all element types, removing references and const.
This amendment partially addresses this issue:
template<std::size_t N, class Tuple, typename S>
auto replace_tuple_element(Tuple&& tuple, S&& s) {
using T = std::remove_reference_t<Tuple>;
auto get_element = [&tuple, &s]<std::size_t i>(index<i>) {
if constexpr (i == N)
return std::forward<S>(s);
else
if constexpr (std::is_lvalue_reference_v<std::tuple_element_t<i, T>>)
return std::ref(std::get<i>(std::forward<Tuple>(tuple)));
else
return std::get<i>(std::forward<Tuple>(tuple));
};
return [&get_element]<std::size_t... is>(std::index_sequence<is...>) {
return std::make_tuple(get_element(index<is>{})...);
}(std::make_index_sequence<std::tuple_size_v<T>>{});
}
Now replace_tuple_element also follows the convention of std::make_tuple that converts std::reference_wrapper arguments into references. It does preserve reference types, but drops top-level constness.
struct Foo {
Foo(int i) : value(i) {}
int value;
};
int main() {
int i = 1;
int j = 2;
auto t1 = std::make_tuple(std::make_unique<Foo>(0), std::ref(i), std::cref(j), 4);
static_assert(std::is_same_v<decltype(t1),
std::tuple<std::unique_ptr<Foo>, int&, const int&, int>>);
auto t2 = replace_tuple_element<1>(std::move(t1), std::make_unique<Foo>(5));
static_assert(std::is_same_v<decltype(t2),
std::tuple<std::unique_ptr<Foo>, std::unique_ptr<Foo>, const int&, int>>);
auto t3 = replace_tuple_element<0>(std::move(t2), std::cref(i));
static_assert(std::is_same_v<decltype(t3),
std::tuple<const int&, std::unique_ptr<Foo>, const int&, int>>);
auto t4 = replace_tuple_element<2>(std::move(t3), i);
static_assert(std::is_same_v<decltype(t4),
std::tuple<const int&, std::unique_ptr<Foo>, int, int>>);
}
Full demo with run-time asserts
This should do it:
template<std::size_t N, class U, class T>
auto replace_tuple_element(T&& t, U&& u) {
return [&]<std::size_t... I>(std::index_sequence<I...>) {
return std::tuple<std::conditional_t<I == N, U, std::tuple_element_t<I, std::decay_t<T>>>...>{
[&]() -> decltype(auto) {
if constexpr (I == N) return std::forward<U>(u);
else return static_cast<std::tuple_element_t<I, std::decay_t<T>>>(std::get<I>(t));
}()...};
}(std::make_index_sequence<std::tuple_size_v<std::decay_t<T>>>{});
}
You can remove some of the casts, forwards etc. if you're only concerned with value semantics.
The only thing new here is lambda template parameters to infer the indexing argument.
If we want to both preserve all the types exactly as they are, and also do the same kind of reference unwrapping thing that the standard library typically does, then we need to make a small change to what the other implementations are here.
unwrap_ref_decay will do a decay_t on the type, and then turn reference_wrapper<T> into T&. And using Boost.Mp11 for a few things that just make everything nicer:
template <size_t N, typename OldTuple, typename NewType>
constexpr auto replace_tuple_element(OldTuple&& tuple, NewType&& elem)
{
using Old = std::remove_cvref_t<OldTuple>;
using R = mp_replace_at_c<Old, N, std::unwrap_ref_decay_t<NewType>>;
static constexpr auto Size = mp_size<Old>::value;
auto get_nth = [&](auto I) -> decltype(auto) {
if constexpr (I == N) return std::forward<NewType>(elem);
else return std::get<I>(std::forward<OldTuple>(tuple));
};
return [&]<size_t... Is>(std::index_sequence<Is...>) {
return R(get_nth(mp_size_t<Is>())...);
}(std::make_index_sequence<Size>());
}
This implementation means that given:
std::tuple<int const, int const> x(1, 2);
int i = 42;
auto y = replace_tuple_element<1>(x, std::ref(i));
y is a tuple<int const, int&>.
This is a good use case for a counterpart of tuple_cat that, instead of concatenating tuples, gives you a slices of a tuple. Unfortunately, this doesn't exist in the standard library, so we'll have to write it ourselves:
template <std::size_t Begin, std::size_t End, typename Tuple>
constexpr auto tuple_slice(Tuple&& t)
{
return [&]<std::size_t... Ids> (std::index_sequence<Ids...>)
{
return std::tuple<std::tuple_element_t<Ids, std::remove_reference_t<Tuple>>...>
{std::get<Begin + Ids>(std::forward<Tuple>(t))...};
} (std::make_index_sequence<End - Begin>{});
}
Just like tuple_cat, this preserve the exact same types of the original tuple.
With tuple_cat and tuple_slice, the implementation of replace_tuple_element feels quite elegant:
template <std::size_t N, typename Tuple, typename T>
constexpr auto replace_tuple_element(Tuple&& tuple, T&& t)
{
constexpr auto Size = std::tuple_size_v<std::remove_reference_t<Tuple>>;
return std::tuple_cat(
tuple_slice<0, N>(std::forward<Tuple>(tuple)),
std::make_tuple(std::forward<T>(t)),
tuple_slice<N + 1, Size>(std::forward<Tuple>(tuple))
);
}
Using make_tuple preserves the behavior of turning reference_wrapper<T> into T&. Demo

How to iterate over the types of std::variant?

I have some variant using V = std::variant<A, B, C> and a function with the prototype V parse(const json&). The function should try to parse all the types (e.g. A, B, then C) till the first success (and it should do it implicitly, for there will be many types in time).
How to implement something of this kind?
We may use std::variant_size somehow.
Here is something close to what I need.
My solution is to list parsers of all the types explicitly.
V parse(const json& i_j)
{
using Parser = std::function<MaybeV(const json&)>;
static const auto ps = std::vector<Parser>{
[](const auto& j)->MaybeV{return j.get<std::optional<A>>;},
[](const auto& j)->MaybeV{return j.get<std::optional<B>>;},
[](const auto& j)->MaybeV{return j.get<std::optional<C>>;}
};
for (const auto& p : ps)
if (auto opt_result = p(i_j))
return std::move(*opt_result);
throw ParseError("Can't parse");
}
Yet it may definitely be simplified, for the lambdas different only in type and what I actually need is to iterate over the types of std::variant.
You want compile time integers from 0 to variant's size minus 1, and possibly early exit from iterating over them.
There are lots of ways to get compile time integers. Two of my favorites are generating a tuple of integral constants, or calling a continuation with a parameter pack of integral constants.
Taking the tuple of integral constants version, you can use a "tuple for each" to visit each in turn.
template<std::size_t I>
using index_t = std::integral_constant<std::size_t, I>;
template<std::size_t I>
constexpr index_t<I> index{};
template<std::size_t...Is>
constexpr std::tuple< index_t<Is>... > make_indexes(std::index_sequence<Is...>){
return std::make_tuple(index<Is>...);
}
template<std::size_t N>
constexpr auto indexing_tuple = make_indexes(std::make_index_sequence<N>{});
from variant size you call that. From that you call a tuple_foreach.
The tuple_foreach emplaces the optional return value if parsing succeeds and it wasn't already parsed.
V parse(const json& j)
{
auto indexes = indexing_tuple<tuple_size_v<V>>;
std::optional<V> retval;
tuple_foreach(indexes, [&](auto I){ // I is compile time integer
if(retval) return;
auto p = j.get<tuple_alternative_t<I>>();
if(p) retval.emplace(std::move(*p));
});
if(!retval) throw ParseError("Can't parse");
return std::move(*retval);
}
tuple_foreach can be found on the internet, but for completeness:
template<std::size_t...Is, class T, class F>
auto tuple_foreach( std::index_sequence<Is...>, T&& tup, F&& f ) {
( f( std::get<Is>( std::forward<T>(tup) ) ), ... );
}
template<class T, class F>
auto tuple_foreach( T&& tup, F&& f ) {
auto indexes = std::make_index_sequence< std::tuple_size_v< std::decay_t<T> > >{};
return tuple_foreach( indexes, std::forward<T>(tup), std::forward<F>(f) );
}
which should do it in c++17.
Types can be processed recursively from 0 to std::variant_size_v (exclusive), with an if-constexpr limiting template instantiations:
#include <variant>
#include <optional>
#include <cstddef>
#include <utility>
using V = std::variant<A, B, C>;
template <std::size_t I = 0>
V parse(const json& j)
{
if constexpr (I < std::variant_size_v<V>)
{
auto result = j.get<std::optional<std::variant_alternative_t<I, V>>>();
return result ? std::move(*result) : parse<I + 1>(j);
}
throw ParseError("Can't parse");
}
DEMO

Constructing an iterator_range with variadic templates and runtime indices

I have a collection of equally-sized vectors and want to provide an interface for the user to obtain an iterator range over a subset of these vectors.
The following example shows the problematic line inside getRange: its idea is to receive a bunch of types (specifying the types of vectors) and equally many indices (specifying the locations of the vectors). The code compiles, but the problem is that i++ never gets executed as intended, i.e., the call is always with just i (which equals 0). This will also lead to runtime errors via boost::get if the user tries to get distinct types.
This is probably a well-known issue. What's a neat solution to it?
#include <vector>
#include <boost/variant.hpp>
#include <boost/range/combine.hpp>
template <typename... T>
struct VectorHolder
{
template<typename X>
using Iterator = typename std::vector<X>::const_iterator;
std::vector<boost::variant<std::vector<T>...> > vecs_;
template <typename X>
auto begin(int idx) const {
return boost::get<std::vector<X> >(vecs_.at(idx)).cbegin();
}
template <typename X>
auto end(int idx) const {
return boost::get<std::vector<X> >(vecs_.at(idx)).cend();
}
};
template <typename... T, typename VectorHolder>
auto getRange(const VectorHolder& vh, const std::vector<int>& idx)
{
assert(sizeof...(T) == idx.size());
// Fetch a boost::iterator_range over the specified indices
std::size_t i = 0;
std::size_t j = 0;
// PROBLEM: i and j not incremented as intended
return boost::combine(
boost::iterator_range<VectorHolder::Iterator<T>>(
vh.begin<T>(idx[i++]), vh.end<T>(idx[j++]))...);
}
int main()
{
VectorHolder<bool, int, double> vh;
vh.vecs_.push_back(std::vector<int>(5, 5));
vh.vecs_.push_back(std::vector<bool>(5));
vh.vecs_.push_back(std::vector<double>(5, 2.2));
vh.vecs_.push_back(std::vector<int>(5, 1));
const std::vector<int> idx = { 0, 3 };
for (auto t : getRange<int, int>(vh, idx))
{
std::cout << t.get<0>() << " " << t.get<1>() << "\n";
}
}
std::index_sequence helps:
template <typename... Ts, typename VectorHolder, std::size_t ... Is>
auto getRange(const VectorHolder& vh, const std::vector<int>& idx, std::index_sequence<Is...>)
{
assert(sizeof...(Ts) == idx.size());
return boost::combine(
boost::iterator_range<typename VectorHolder::template Iterator<Ts>>(
vh.template begin<Ts>(idx[Is]), vh.template end<Ts>(idx[Is]))...);
}
template <typename... Ts, typename VectorHolder>
auto getRange(const VectorHolder& vh, const std::vector<int>& idx)
{
return getRange<Ts...>(vh, idx, std::index_sequence_for<Ts...>());
}
Demo

How do I bind a ::std::vector of arguments to a functor?

I'm trying to make this program compile properly:
#include <vector>
#include <iostream>
int f(int a, int b)
{
::std::cout << "f(" << a << ", " << b << ") == " << (a + b) << '\n';
return a + b;
}
template <typename R, typename V>
R bind_vec(R (*f)(), const V &vec, int idx=0)
{
return f();
}
template <typename R, typename V, typename Arg1, typename... ArgT>
R bind_vec(R (*f)(Arg1, ArgT...), const V &vec, int idx=0)
{
const Arg1 &arg = vec[idx];
auto call = [arg, f](ArgT... args) -> R {
return (*f)(arg, args...);
};
return bind_vec(call, vec, idx+1);
}
int foo()
{
::std::vector<int> x = {1, 2};
return bind_vec(f, x);
}
Ideally I'd like bind_vec to take an arbitrary functor as an argument instead of just a function pointer. The idea is to pull the function arguments from a ::std::vector at compile time.
This isn't the final use for this, but it's a stepping stone to where I want to go. What I'm really doing is generating wrapper functions that unwrap their arguments from promises in a future/promise type system at compile time. These wrapper functions will themselves be promises.
In my ultimate use-case I can count on the functors being ::std::functions. But it would be nice to have an idea of how it should work for more general functors as well since I think this is a broadly interesting problem.
OK, first off, detecting the arity of a functor can be done, but it's a bit involved and best left to a separate question. Let's assume you will specify the arity of the functor in the call. Similarly, there are ways to obtain the return type of a callable object, but that's also beyond the scope of this question. Let's just assume the return type is void for now.
So we want to say,
call(F f, C v);
and that should say f(v[0], v[1], ..., v[n-1]), where f has arity n.
Here's an approach:
template <unsigned int N, typename Functor, typename Container>
void call(Functor const & f, Container const & c)
{
call_helper<N == 0, Functor, Container, N>::engage(f, c);
}
We need the helper:
#include <functional>
#include <cassert>
template <bool Done, typename Functor, typename Container,
unsigned int N, unsigned int ...I>
struct call_helper
{
static void engage(Functor const & f, Container const & c)
{
call_helper<sizeof...(I) + 1 == N, Functor, Container,
N, I..., sizeof...(I)>::engage(f, c);
}
};
template <typename Functor, typename Container,
unsigned int N, unsigned int ...I>
struct call_helper<true, Functor, Container, N, I...>
{
static void engage(Functor const & f, Container const & c)
{
assert(c.size() >= N);
f(c[I]...);
}
};
Example:
#include <vector>
#include <iostream>
void f(int a, int b) { std::cout << "You said: " << a << ", " << b << "\n"; }
struct Func
{
void operator()(int a, int b) const
{ std::cout << "Functor: " << a << "::" << b << "\n"; }
};
int main()
{
std::vector<int> v { 20, 30 };
call<2>(f, v);
call<2>(Func(), v);
}
Notes: In a more advanced version, I would deduce the arity of the callable object with some more template machinery, and I would also deduce the return type. For this to work, you'll need several specializations for free functions and various CV-qualified class member functions, though, and so this would be getting too large for this question.
Something like this is easily possible for (member) function pointers, but for functors with potentially overloaded operator(), this gets a dang lot harder. If we assume that you have a way to tell how many arguments a function takes (and assume that the container actually has that many elements), you can just use the indices trick to expand the vector into an argument list, for example with std::next and a begin() iterator:
#include <utility>
#include <iterator>
template<class F, class Args, unsigned... Is>
auto invoke(F&& f, Args& cont, seq<Is...>)
-> decltype(std::forward<F>(f)(*std::next(cont.begin(), Is)...))
{
return std::forward<F>(f)(*std::next(cont.begin(), Is)...);
}
template<unsigned ArgC, class F, class Args>
auto invoke(F&& f, Args& cont)
-> decltype(invoke(std::forward<F>(f), cont, gen_seq<ArgC>{}))
{
return invoke(std::forward<F>(f), cont, gen_seq<ArgC>{});
}
This implementation works really nice for random-access containers, but not so well for forward and especially input ones. To make those work in a performant fashion, you might try to go the route of incrementing the iterator with every expanded step, but you'll run into a problem: Evaluation order of arguments to a function is unspecified, so you'll very likely pass the arguments in the wrong order.
Luckily, there is a way to force evaluation left-to-right: The list-initialization syntax. Now we just need a context where that can be used to pass arguments, and a possible one would be to construct an object, pass the function and the arguments through the constructor, and call the function in there. However, you lose the ability to retrieve the returned value, since constructors can't return a value.
Something I thought of is to create an array of iterators, which point to the correct element, and expanding those again in a second step where they are dereferenced.
#include <utility>
template<class T> using Alias = T; // for temporary arrays
template<class F, class It, unsigned N, unsigned... Is>
auto invoke_2(F&& f, It (&&args)[N], seq<Is...>)
-> decltype(std::forward<F>(f)(*args[Is]...))
{
return std::forward<F>(f)(*args[Is]...);
}
template<class F, class Args, unsigned... Is>
auto invoke_1(F&& f, Args& cont, seq<Is...> s)
-> decltype(invoke_2(std::forward<F>(f), std::declval<decltype(cont.begin())[sizeof...(Is)]>(), s))
{
auto it = cont.begin();
return invoke_2(std::forward<F>(f), Alias<decltype(it)[]>{(void(Is), ++it)...}, s);
}
template<unsigned ArgC, class F, class Args>
auto invoke(F&& f, Args& cont)
-> decltype(invoke_1(std::forward<F>(f), cont, gen_seq<ArgC>{}))
{
return invoke_1(std::forward<F>(f), cont, gen_seq<ArgC>{});
}
The code was tested against GCC 4.7.2 and works as advertised.
Since you said that the functors you are getting passed are std::functions, getting the number of arguments they take is really easy:
template<class F> struct function_arity;
// if you have the 'Signature' of a 'std::function' handy
template<class R, class... Args>
struct function_arity<R(Args...)>
: std::integral_constant<std::size_t, sizeof...(Args)>{};
// if you only have the 'std::function' available
template<class R, class... Args>
struct function_arity<std::function<R(Args...)>>
: function_arity<R(Args...)>{};
Note that you don't even need function_arity to make invoke from above work for std::function:
template<class R, class... Ts, class Args>
R invoke(std::function<R(Ts...)> const& f, Args& cont){
return invoke_1(f, cont, gen_seq<sizeof...(Ts)>{})
}
I managed to do what you want. It's simplest to explain if I leave it as not deducing the correct return type at first, I'll show how to add that later on:
#include <vector>
#include <type_traits>
namespace {
int f(int a, int b) { return 0; }
}
template <typename ...Args>
constexpr unsigned nb_args(int (*)(Args...)) {
return sizeof...(Args);
}
template <typename F, typename V, typename ...Args>
auto bind_vec(F f, const V&, Args&& ...args)
-> typename std::enable_if<sizeof...(Args) == nb_args(F()),void>::type
{
f(std::forward<Args>(args)...);
}
template <typename F, typename V, typename ...Args>
auto bind_vec(F f, const V& v, Args&& ...args)
-> typename std::enable_if<sizeof...(Args) < nb_args(F()),void>::type
{
bind_vec(f, v, std::forward<Args>(args)..., v.at(sizeof...(Args)));
}
int main() {
bind_vec(&f, std::vector<int>(), 1);
return 0;
}
There are two versions of this bind_vec - one is enabled if the parameter pack is the right size for the function. The other is enabled if it is still too small. The first version simply dispatches the call using the parameter pack, whilst the second version gets the next element (as determined by the size of the parameter pack) and recurses.
There SFINAE is done on the return type of the function in order that it not interfer with the deduction of the types, but this means it needs to be done after the function since it needs to know about F. There's a helper function that finds the number of arguments needed to call a function pointer.
To deduce the return types also we can use decltype with the function pointer:
#include <vector>
#include <type_traits>
namespace {
int f(int a, int b) { return 0; }
}
template <typename ...Args>
constexpr unsigned nb_args(int (*)(Args...)) {
return sizeof...(Args);
}
template <typename F, typename V, typename ...Args>
auto bind_vec(F f, const V&, Args&& ...args)
-> typename std::enable_if<sizeof...(Args) == nb_args(F()),decltype(f(std::forward<Args>(args)...))>::type
{
return f(std::forward<Args>(args)...);
}
template <typename F, typename V, typename ...Args>
auto bind_vec(F f, const V& v, Args&& ...args)
-> typename std::enable_if<sizeof...(Args) < nb_args(F()),decltype(bind_vec(f, v, std::forward<Args>(args)..., v.at(sizeof...(Args))))>::type
{
return bind_vec(f, v, std::forward<Args>(args)..., v.at(sizeof...(Args)));
}
int main() {
bind_vec(&f, std::vector<int>(), 1);
return 0;
}

In C++, is it possible to get the type of one element of a tuple when the element index is known at runtime?

typedef std::tuple< int, double > Tuple;
Tuple t;
int a = std::get<0>(t);
double b = std::get<1>(t);
for( size_t i = 0; i < std::tuple_size<Tuple>::value; i++ ) {
std::tuple_element<i,Tuple>::type v = std::get<i>(t);// will not compile because i must be known at compile time
}
I know it is possible to write code for get std::get working (see for example iterate over tuple ), is it possible to get std::tuple_element working too?
Some constraints (they can be relaxed):
no variadic templates, no Boost
C++ is a compile-time typed language. You cannot have a type that the C++ compiler cannot determine at compile-time.
You can use polymorphism of various forms to work around that. But at the end of the day, every variable must have a well-defined type. So while you can use Boost.Fusion algorithms to iterate over variables in a tuple, you cannot have a loop where each execution of the loop may use a different type than the last.
The only reason Boost.Fusion can get away with it is because it doesn't use a loop. It uses template recursion to "iterate" over each element and call your user-provided function.
If you want to do without boost, the answers to iterate over tuple already tell you everything you need to know. You have to write a compile-time for_each loop (untested).
template<class Tuple, class Func, size_t i>
void foreach(Tuple& t, Func fn) {
// i is defined at compile-time, so you can write:
std::tuple_element<i, Tuple> te = std::get<i>(t);
fn(te);
foreach<i-1>(t, fn);
}
template<class Tuple, class Func>
void foreach<0>(Tuple& t, Func fn) { // template specialization
fn(std::get<0>(t)); // no further recursion
}
and use it like that:
struct SomeFunctionObject {
void operator()( int i ) const {}
void operator()( double f ) const {}
};
foreach<std::tuple_size<Tuple>::value>(t, SomeFunctionObject());
However, if you want to iterate over members of a tuple, Boost.Fusion really is the way to go.
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/adapted/boost_tuple.hpp>
and in your code write:
boost::for_each(t, SomeFunctionObject());
This an example for boost::tuple. There is an adapter for boost::fusion to work with the std::tuple here: http://groups.google.com/group/boost-list/browse_thread/thread/77622e41af1366af/
No, this is not possible the way you describe it. Basically, you'd have to write your code for every possible runtime-value of i and then use some dispatching-logic (e.g. switch(i)) to run the correct code based on the actual runtime-value of i.
In practice, it might be possible to generate the code for the different values of i with templates, but I am not really sure how to do this, and whether it would be practical. What you are describing sounds like a flawed design.
Here is my tuple foreach/transformation function:
#include <cstddef>
#include <tuple>
#include <type_traits>
template<size_t N>
struct tuple_foreach_impl {
template<typename T, typename C>
static inline auto call(T&& t, C&& c)
-> decltype(::std::tuple_cat(
tuple_foreach_impl<N-1>::call(
::std::forward<T>(t), ::std::forward<C>(c)
),
::std::make_tuple(c(::std::get<N-1>(::std::forward<T>(t))))
))
{
return ::std::tuple_cat(
tuple_foreach_impl<N-1>::call(
::std::forward<T>(t), ::std::forward<C>(c)
),
::std::make_tuple(c(::std::get<N-1>(::std::forward<T>(t))))
);
}
};
template<>
struct tuple_foreach_impl<0> {
template<typename T, typename C>
static inline ::std::tuple<> call(T&&, C&&) { return ::std::tuple<>(); }
};
template<typename T, typename C>
auto tuple_foreach(T&& t, C&& c)
-> decltype(tuple_foreach_impl<
::std::tuple_size<typename ::std::decay<T>::type
>::value>::call(std::forward<T>(t), ::std::forward<C>(c)))
{
return tuple_foreach_impl<
::std::tuple_size<typename ::std::decay<T>::type>::value
>::call(::std::forward<T>(t), ::std::forward<C>(c));
}
The example usage uses the following utility to allow printing tuples to ostreams:
#include <cstddef>
#include <ostream>
#include <tuple>
#include <type_traits>
template<size_t N>
struct tuple_print_impl {
template<typename S, typename T>
static inline void print(S& s, T&& t) {
tuple_print_impl<N-1>::print(s, ::std::forward<T>(t));
if (N > 1) { s << ',' << ' '; }
s << ::std::get<N-1>(::std::forward<T>(t));
}
};
template<>
struct tuple_print_impl<0> {
template<typename S, typename T>
static inline void print(S&, T&&) {}
};
template<typename S, typename T>
void tuple_print(S& s, T&& t) {
s << '(';
tuple_print_impl<
::std::tuple_size<typename ::std::decay<T>::type>::value
>::print(s, ::std::forward<T>(t));
s << ')';
}
template<typename C, typename... T>
::std::basic_ostream<C>& operator<<(
::std::basic_ostream<C>& s, ::std::tuple<T...> const& t
) {
tuple_print(s, t);
return s;
}
And finally, here is the example usage:
#include <iostream>
using namespace std;
struct inc {
template<typename T>
T operator()(T const& val) { return val+1; }
};
int main() {
// will print out "(7, 4.2, z)"
cout << tuple_foreach(make_tuple(6, 3.2, 'y'), inc()) << endl;
return 0;
}
Note that the callable object is constructed so that it can hold state if needed. For example, you could use the following to find the last object in the tuple that can be dynamic casted to T:
template<typename T>
struct find_by_type {
find() : result(nullptr) {}
T* result;
template<typename U>
bool operator()(U& val) {
auto tmp = dynamic_cast<T*>(&val);
auto ret = tmp != nullptr;
if (ret) { result = tmp; }
return ret;
}
};
Note that one shortcoming of this is that it requires that the callable returns a value. However, it wouldn't be that hard to rewrite it to detect whether the return type is void for a give input type, and then skip that element of the resulting tuple. Even easier, you could just remove the return value aggregation stuff altogether and simply use the foreach call as a tuple modifier.
Edit:
I just realized that the tuple writter could trivially be written using the foreach function (I have had the tuple printing code for much longer than the foreach code).
template<typename T>
struct tuple_print {
print(T& s) : _first(true), _s(&s) {}
template<typename U>
bool operator()(U const& val) {
if (_first) { _first = false; } else { (*_s) << ',' << ' '; }
(*_s) << val;
return false;
}
private:
bool _first;
T* _s;
};
template<typename C, typename... T>
::std::basic_ostream<C> & operator<<(
::std::basic_ostream<C>& s, ::std::tuple<T...> const& t
) {
s << '(';
tuple_foreach(t, tuple_print< ::std::basic_ostream<C>>(s));
s << ')';
return s;
}