I'm playing around with C++14 lambdas (well just lambdas in general really) and I have a function (pipeline) I'm trying to write. The premise is that it'll take a unit lambda and an array of unary lambdas that it'll then run on the unit and produce a new unit to send into the next in the pipeline until you get through the last lambda and return the final unit. my current code is:
auto pipeline = [](auto u, auto callbacks[]){
for(int i = 0; i<sizeof(callbacks)/sizeof(callbacks[0]);i++){
u = bind(u,callbacks[i]);
}
return u;
};
The current issue is that clang is kicking back on the array saying:
testFuture.cpp:183:111: error: no matching function for call to object of type 'func::<lambda at ./func.hpp:30:19>'
cout<<"pipeline(unit(10),{addf(4),curry(mul,2)}):"<<bind(unit(bind(unit(10))(addf(4))))(curry(mul,2))<<"|"<<pipeline(unit(10),{{addf(4),curry(mul,2)}})()<<endl;
^~~~~~~~
./func.hpp:30:19: note: candidate template ignored: couldn't infer template argument '$auto-0-1'
auto pipeline = [](auto u, auto callbacks[]){
^
1 error generated.
Is this simply not possible with lambdas? Do I need to whip out std::function? Am I just going about this the wrong way?
Taking a step back, you’re attempting to perform a (left) fold over a sequence of values. Because in C++ each closure has a unique type, you want to make that fold over a tuple, not an array. As an added benefit, we will be more general and accept functors with any return type, which we couldn’t if e.g. we used std::function to emulate arrow types.
#include <utility> // std::forward, std::integer_sequence
#include <type_traits> // std::remove_reference_t
#include <tuple> // tuple protocol, e.g. std::get, std::tuple_size
namespace detail {
template<typename Functor, typename Zero, typename Tuple, typename Int>
Zero foldl(Functor&&, Zero&& zero, Tuple&&, std::integer_sequence<Int>)
{ return std::forward<Zero>(zero); }
template<typename Functor, typename Zero, typename Tuple, typename Int, Int Index, Int... Indices>
decltype(auto) foldl(Functor&& functor, Zero&& zero, Tuple&& tuple, std::integer_sequence<Int, Index, Indices...>)
{ return detail::foldl(
functor
, functor(std::forward<Zero>(zero), std::get<Index>(std::forward<Tuple>(tuple)))
, std::forward<Tuple>(tuple)
, std::integer_sequence<Int, Indices...> {}); }
} // detail
template<typename Functor, typename Zero, typename Tuple>
decltype(auto) foldl(Functor&& functor, Zero&& zero, Tuple&& tuple)
{
return detail::foldl(
std::forward<Functor>(functor)
, std::forward<Zero>(zero)
, std::forward<Tuple>(tuple)
, std::make_index_sequence<std::tuple_size<std::remove_reference_t<Tuple>>::value>()
);
}
You haven’t told us what bind is supposed to achieve, but here’s an example involving reverse composition of functions. (Included is a limited implementation of integer_sequence and friends as they don’t appear to be available on Coliru — type traits aliases are missing as well.)
Related
For some personal reasons, I working on a C++ version of the Julia's SparseMatrixCSC that is specific in a project that I port to C++ and where the Armadillo's SpMat failed to be a perfect alternative.
template <typename Tv, typename Ti>
struct SparseMatrixCSC
{
size_t m, n;
arma::Col<Ti> colptr;
arma::Col<Ti> rowval;
arma::Col<Tv> nzval;
};
Some Julia functions like the blockdiag() allow a variadic-like number of sparse matrix in input and one 'blockdiag' matrix in output. The scripting code of Julia allow some generic method that can be ported easily with C++17 like collecting the size of the n-matrix in input, for example :
template <typename... Args>
constexpr auto blockdiag(const Args& ...args)
{
auto mX = details::apply([](auto x) { return size(x, 1); }, args...);
auto nX = details::apply([](auto x) { return size(x, 2); }, args...);
auto m = sum(mX);
auto n = sum(nX);
...
Where the internal details::apply function allow to recursively collect the rows/cols on the input n-matrix. The final matrix dimension is summed in m and n. No problem, the code works perfectly.
But now, my problem is to compute the typename parameters of the ouput matrix by collecting/promoting the types Tv (value) and Ti (indexing) from something similar function. By nature of sparsity matrix, the Tv and Ti types are numerical values. And more specificaly, Ti is an integral type.
As I understand, because i'm a true newbie in metaprogramming with the latest standards of C++, the best way to do that is to use the <type_traits> std::common_type. But I don't see how to unpack my variadic template args (that contain the SparseMatrixCSC) and expand the std::common_type<...> parameters with the result of the functor that get the decltype of one or another internal column vector arma::Col<T>. Something like :
template <typename Func, typename ... Args>
constexpr auto promote_type(Func f, Args const&... args)
{
return typename std::common_type<(f(args), ...)>::type;
}
Called in the previous blockdiag function by:
typename Tv = details::promote_type([](auto x) { return decltype(x.nzval); }, args...);
typename Ti = details::promote_type([](auto x) { return decltype(x.rowval); }, args...);
Unfortunately, too bad for the VS2019 16.5.4 compiler. More, I'm pretty sure that the fold expression (f(args), ...) is invalid and cannot be used as template parameter.
So, I need you help, and I thank you very much for that.
EDIT:
To answer Barry, the promote_type is a Julia's function described like that :
Promotion refers to converting values of mixed types to a single
common type. promote_type represents the default promotion behavior in
Julia when operators (usually mathematical) are given arguments of
differing types. promote_type generally tries to return a type which
can at least approximate most values of either input type without
excessively widening. Some loss is tolerated; for example,
promote_type(Int64, Float64) returns Float64 even though strictly, not
all Int64 values can be represented exactly as Float64 values.
Since each of the args... here:
template <typename... Args>
constexpr auto blockdiag(const Args& ...args)
is itself a SparseMatrixCSC, let's make that more explicit:
template <typename... T, typename... U>
constexpr auto blockdiag(const SparseMatrixCSC<T, U>& ...args)
This both makes the requirements of blockdiag easier to understand (now we know what it takes) and makes it easier to figure out the answer: we have the Ts and Us right there, so just use 'em:
template <typename... T, typename... U>
constexpr auto blockdiag(const SparseMatrixCSC<T, U>& ...args)
-> SpareMatrixCSC<std::common_type_t<T...>, std::common_type_t<U...>>;
Let's say I use std::forward_as_tuple to store the arguments of a function call in a tuple
auto args = std::forward_as_tuple(std::forward<Args>(args)...);
And then I pass this tuple by lvalue reference to a function that wants to invoke a function foo() with some of the arguments in args as determined by another std::integer_sequence. I do it with std::move() like so
template <typename TupleArgs, std::size_t... Indices>
decltype(auto) forward_to_foo(TupleArgs&& args,
std::index_sequence<Indices...>) {
return foo(std::get<Indices>(std::move(args))...);
}
And this would work because the rvalue qualified version of std::get<std::tuple> return std::tuple_element_t<Index, tuple<Types...>>&& which is an identity transformation of the reference-ness of the std::tuple_element_t<Index, tuple<Types...>> because of reference collapsing with the &&.
So if std::tuple_element_t<Index, tuple<Types...>> evaluates to T& the returned type would be T& && which is just T&. Similar reason for when std::tuple_element_t<Index, tuple<Types...>> returns T&& and T
Am I missing something? Are there some cases where this would fail?
template <typename TupleArgs, std::size_t... Indices>
decltype(auto) forward_to_foo(TupleArgs&& args,
std::index_sequence<Indices...>) {
return foo(std::get<Indices>(std::forward<TupleArgs>(args))...);
}
This is the correct implementation.
Use should look like:
auto tuple_args = std::forward_as_tuple(std::forward<Args>(args)...);
forward_to_foo( std::move(tuple_args), std::make_index_sequence<sizeof...(args)>{} );
there are a few differences here.
First, we take by forwarding reference, not by lvalue reference. This lets the caller provide rvalue (prvalue or xvalue) tuples to us.
Second, we forward the tuple into the std::get call. This means we only pass get an rvalue reference if the tuple was moved into us.
Third, we move into forward_to_foo. This ensures the above does the right thing.
Now, imagine if we wanted to call foo twice.
auto tuple_args = std::forward_as_tuple(std::forward<Args>(args)...);
auto indexes = std::make_index_sequence<sizeof...(args)>{};
forward_to_foo( tuple_args, indexes );
forward_to_foo( std::move(tuple_args), indexes );
we don't have to touch forward_to_foo at all, and we never move from any of the args more than once.
With your original implementation, any calls to forward_to_foo silently move from TupleArgs rvalue references or values without any indication at the call-site that we are destructive on the first parameter.
Other than that detail, yes that emulates forwarding.
Myself I'd just write a notstd::apply:
namespace notstd {
namespace details {
template <class F, class TupleArgs, std::size_t... Indices>
decltype(auto) apply(F&& f, TupleArgs&& args,
std::index_sequence<Indices...>) {
return std::forward<F>(f)(std::get<Indices>(std::forward<TupleArgs>(args))...);
}
}
template <class F, class TupleArgs>
decltype(auto) apply(F&& f, TupleArgs&& args) {
constexpr auto count = std::tuple_size< std::decay_t<TupleArgs> >{};
return details::apply(
std::forward<F>(f),
std::forward<TupleArgs>(args),
std::make_index_sequence< count >{}
);
}
}
then we do:
auto tuple_args = std::forward_as_tuple(std::forward<Args>(args)...);
auto call_foo = [](auto&&...args)->decltype(auto){ return foo(decltype(args)(args)...); };
return notstd::apply( call_foo, std::move(tuple_args) );
which moves the tricky bit into notstd::apply, which attempts to match the semantics of std::apply, which lets you replace it down the road with a more standard bit of code.
While trying to reply to this question, I found my self in the need of creating a bunch of parameters for a variadic function on the fly where:
the number of the parameters is not given
the types are all the same, but unknown (even if they must be default constructible)
At runtime, the standard containers and a for loop can be used to do that.
Anyway, I'd like to generate a set of parameters at compile time, so as to be able to forward them to a variadic function.
Because of that, a std::tuple seemed the obvious solution.
Here arose the question: given a size N and a default constructible type T at compile time, how can I write a function to generate a tuple of the given size?
I'm looking for something like this:
auto tup = gen<MyType, N>();
On SO is a notable example of a recursive generator based structs but I was struggling with a function based solution and I've not been able to find it anywhere.
A correctly written forwarding function (a la std::apply) should work with std::array<T, N> and anything else that implements the std::tuple_size/std::get interface. That said,
template<size_t, class T>
using T_ = T;
template<class T, size_t... Is>
auto gen(std::index_sequence<Is...>) { return std::tuple<T_<Is, T>...>{}; }
template<class T, size_t N>
auto gen() { return gen<T>(std::make_index_sequence<N>{}); }
Here is a possible implementation of such a function:
#include<utility>
#include<tuple>
template<typename T>
constexpr auto
params(std::index_sequence<0>) {
return std::tuple<T>{};
}
template<typename T, std::size_t I, std::size_t... O>
constexpr auto
params(std::index_sequence<I, O...>) {
auto tup = std::tuple<T>{ T{} };
auto seq = std::make_index_sequence<sizeof...(O)>{};
return std::tuple_cat(tup, params<T>(seq));
}
template<typename T, std::size_t N>
constexpr auto
gen(std::integral_constant<std::size_t, N>) {
return params<T>(std::make_index_sequence<N>{});
}
int main() {
auto tup = gen<int>(std::integral_constant<std::size_t, 3>{});
static_assert(std::tuple_size<decltype(tup)>::value == 3, "!");
}
For the sake of simplicity, I've used int as a type.
With a small effort, user defined types can be used and the constraint of having them default constructible can be relaxed.
I'm trying to invoke two functional objects through one given argument pack (typename Args... args), an integer parameter is provided to mark the border where i need to split the pack to invoke both functional objects correctly.
Consider the following example:
Args... = <int, int, std::vector<int>, std::vector<int>>
unsigned Bounds = 2;
functor Foo (left) and Bar (right)
// Foo is invoked with <int, int>
// Bar is invoked with <std::vector<int>, std::vector<int>>
// An evaluator template class is invoked to merge the result of both,
// for example with an add (operator+) operation
My idea was to create two integer sequences and use std::get to invoke both functional objects at once with those two integer sequences:
// Sequence creator
template<unsigned Position, unsigned Count, unsigned... Pack>
struct make_sequence
: std::conditional<
Count == 0,
std::common_type<sequence<Pack...>>,
make_sequence<Position + 1, Count - 1, Pack..., Position>
>::type { };
// Create a sequence from inclusive from to exclusive to
template<unsigned InclusiveFrom, unsigned ExclusiveTo>
using make_sequence_from_to_t = typename make_sequence<
InclusiveFrom,
(ExclusiveTo <= InclusiveFrom) ? 0U : (ExclusiveTo - InclusiveFrom)
>::type;
template<typename LeftType, typename RightType, unsigned Bounds, typename Evaluator>
class distribute_functor
{
LeftType left_;
RightType right_;
template<unsigned... LeftSeq, unsigned... RightSeq, typename... Args>
auto internal_invoke(sequence<LeftSeq...>, sequence<RightSeq...>, Args... args)
{
return Evaluator::evaluate(left_(std::get<LeftSeq>(args)...),
// ~~~~~~~~~~~~~~~^^^^^^^~~^^^^~~~~~
// error C3528: 'LeftSeq': the number of
// elements in this pack expansion does not
// match the number of elements in 'args'
right_(std::get<RightSeq>(args)...));
}
public:
template<typename Left, typename Right>
distribute_functor(Left left, Right right)
: left_(std::forward<Left>(left)), right_(std::forward<Right>(right)) { }
template<typename... Args>
auto operator() (Args... args)
{
return internal_invoke(make_sequence_from_to_t<0, Bounds>{},
make_sequence_from_to_t<Bounds, sizeof...(Args)>{},
std::forward<Args>(args)...);
}
};
However the VisualStudio 14 compiler complains about a mismatch between the count of parameters in the arguments pack and in the sequence:
error C3528: 'LeftSeq': the number of elements in this pack expansion does not match the number of elements in 'args'
There is still the way to use std::tuple for the functor invocation which i don't prefer.
Is there another or better way to partial invoke two functional objects in one step from one argument pack?
std::get cannot be used this way.
You should write internal_invoke like this:
template<unsigned... LeftSeq, unsigned... RightSeq, typename ArgsAsTuple>
auto internal_invoke(sequence<LeftSeq...>, sequence<RightSeq...>,ArgsAsTuple&& args) const
{
return Evaluator::evaluate(left_(std::get<LeftSeq>(args)...),
right_(std::get<RightSeq>(args)...));
}
And invoke it with forward_as_tuple:
return internal_invoke(make_sequence_from_to_t<0, Bounds>{},
make_sequence_from_to_t<Bounds, sizeof...(Args)>{},
std::forward_as_tuple(args...));
Explanation:
Two paramter packs of different arity must be expanded separately. When you write std::get<LeftSeq>(args)..., you try to expand together packs of different arity. This cannot be done. You should have wrote std::get<LeftSeq>(args... /* 1st expand/) ... /* 2nd expand */. This is syntactically correct but does not match std::get API. std::forward_as_tuple is there to help you and has been written precisely for those types of use cases.
Edit:
If you want to avoid the tuple, then you must write your own version of std::get to match your need, provided you expand the parameters correctly as I explained above.
This question already has answers here:
How can you iterate over the elements of an std::tuple?
(23 answers)
Closed 8 years ago.
I have made the following tuple:
I want to know how should I iterate over it? There is tupl_size(), but reading the documentation, I didn't get how to utilize it. Also I have search SO, but questions seem to be around Boost::tuple .
auto some = make_tuple("I am good", 255, 2.1);
template<class F, class...Ts, std::size_t...Is>
void for_each_in_tuple(const std::tuple<Ts...> & tuple, F func, std::index_sequence<Is...>){
using expander = int[];
(void)expander { 0, ((void)func(std::get<Is>(tuple)), 0)... };
}
template<class F, class...Ts>
void for_each_in_tuple(const std::tuple<Ts...> & tuple, F func){
for_each_in_tuple(tuple, func, std::make_index_sequence<sizeof...(Ts)>());
}
Usage:
auto some = std::make_tuple("I am good", 255, 2.1);
for_each_in_tuple(some, [](const auto &x) { std::cout << x << std::endl; });
Demo.
std::index_sequence and family are C++14 features, but they can be easily implemented in C++11 (there are many available on SO). Polymorphic lambdas are also C++14, but can be replaced with a custom-written functor.
Here is an attempt to break down iterating over a tuple into component parts.
First, a function that represents doing a sequence of operations in order. Note that many compilers find this hard to understand, despite it being legal C++11 as far as I can tell:
template<class... Fs>
void do_in_order( Fs&&... fs ) {
int unused[] = { 0, ( (void)std::forward<Fs>(fs)(), 0 )... }
(void)unused; // blocks warnings
}
Next, a function that takes a std::tuple, and extracts the indexes required to access each element. By doing so, we can perfect forward later on.
As a side benefit, my code supports std::pair and std::array iteration:
template<class T>
constexpr std::make_index_sequence<std::tuple_size<T>::value>
get_indexes( T const& )
{ return {}; }
The meat and potatoes:
template<size_t... Is, class Tuple, class F>
void for_each( std::index_sequence<Is...>, Tuple&& tup, F&& f ) {
using std::get;
do_in_order( [&]{ f( get<Is>(std::forward<Tuple>(tup)) ); }... );
}
and the public-facing interface:
template<class Tuple, class F>
void for_each( Tuple&& tup, F&& f ) {
auto indexes = get_indexes(tup);
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f) );
}
while it states Tuple it works on std::arrays and std::pairs. It also forward the r/l value category of said object down to the function object it invokes. Also note that if you have a free function get<N> on your custom type, and you override get_indexes, the above for_each will work on your custom type.
As noted, do_in_order while neat isn't supported by many compilers, as they don't like the lambda with unexpanded parameter packs being expanded into parameter packs.
We can inline do_in_order in that case
template<size_t... Is, class Tuple, class F>
void for_each( std::index_sequence<Is...>, Tuple&& tup, F&& f ) {
using std::get;
int unused[] = { 0, ( (void)f(get<Is>(std::forward<Tuple>(tup)), 0 )... }
(void)unused; // blocks warnings
}
this doesn't cost much verbosity, but I personally find it less clear. The shadow magic of how do_in_order works is obscured by doing it inline in my opinion.
index_sequence (and supporting templates) is a C++14 feature that can be written in C++11. Finding such an implementation on stack overflow is easy. A current top google hit is a decent O(lg(n)) depth implementation, which if I read the comments correctly may be the basis for at least one iteration of the actual gcc make_integer_sequence (the comments also point out some further compile-time improvements surrounding eliminating sizeof... calls).
Alternatively we can write:
template<class F, class...Args>
void for_each_arg(F&&f,Args&&...args){
using discard=int[];
(void)discard{0,((void)(
f(std::forward<Args>(args))
),0)...};
}
And then:
template<size_t... Is, class Tuple, class F>
void for_each( std::index_sequence<Is...>, Tuple&& tup, F&& f ) {
using std::get;
for_each_arg(
std::forward<F>(f),
get<Is>(std::forward<Tuple>(tup))...
);
}
Which avoids the manual expand yet compiles on more compilers. We pass the Is via the auto&&i parameter.
In C++1z we can also use std::apply with a for_each_arg function object to do away with the index fiddling.
Here is a similar and more verbose solution than the formerly accepted one given by T.C., which is maybe a little bit easier to understand (-- it's probably the same as thousand others out there in the net):
template<typename TupleType, typename FunctionType>
void for_each(TupleType&&, FunctionType
, std::integral_constant<size_t, std::tuple_size<typename std::remove_reference<TupleType>::type >::value>) {}
template<std::size_t I, typename TupleType, typename FunctionType
, typename = typename std::enable_if<I!=std::tuple_size<typename std::remove_reference<TupleType>::type>::value>::type >
void for_each(TupleType&& t, FunctionType f, std::integral_constant<size_t, I>)
{
f(std::get<I>(std::forward<TupleType>(t)));
for_each(std::forward<TupleType>(t), f, std::integral_constant<size_t, I + 1>());
}
template<typename TupleType, typename FunctionType>
void for_each(TupleType&& t, FunctionType f)
{
for_each(std::forward<TupleType>(t), f, std::integral_constant<size_t, 0>());
}
Usage (with std::tuple):
auto some = std::make_tuple("I am good", 255, 2.1);
for_each(some, [](const auto &x) { std::cout << x << std::endl; });
Usage (with std::array):
std::array<std::string,2> some2 = {"Also good", "Hello world"};
for_each(some2, [](const auto &x) { std::cout << x << std::endl; });
DEMO
General idea: as in the solution of T.C., start with an index I=0 and go up to the size of the tuple. However, here it is done not per variadic expansion but one-at-a-time.
Explanation:
The first overload of for_each is called if I is equal to the size of the tuple. The function then simply does nothing and such end the recursion.
The second overload calls the function with the argument std::get<I>(t) and increases the index by one. The class std::integral_constant is needed in order to resolve the value of I at compile time. The std::enable_if SFINAE stuff is used to help the compiler separate this overload from the previous one, and call this overload only if the I is smaller than the tuple size (on Coliru this is needed, whereas in Visual Studio it works without).
The third starts the recursion with I=0. It is the overload which is usually called from outside.
EDIT: I've also included the idea mentioned by Yakk to additionally support std::array and std::pair by using a general template parameter TupleType instead of one that is specialized for std::tuple<Ts ...>.
As TupleType type needs to be deduced and is such a "universal reference", this further has the advantage that one gets perfect forwarding for free. The downside is that one has to use another indirection via typename std::remove_reference<TupleType>::type, as TupleType might also be a deduced as a reference type.