Get Last element of parameter pack in C++17 / C++20 - c++

I would like to get the last element of a parameter pack. I did it with the following code GodBolt:
template<typename... Args>
auto last(Args&&... args){
const auto& last = (args, ...);
return last;
}
But now I get the warning
left operand of comma operator has no effect
But this is exactly what I wanted to achieve... Is there a way to make it clear.
In general I like to get warnings for unused values so I don't want to disable all of them (-Wno-unused-value).
In addition I could do it with a recursive template, but a fold expression seems to be better here.

Wrapping args in any function call would remove the warning.
You could make an identity function specifically for this purpose, but you might as well use std::forward and get proper forwarding as a bonus.
template<typename... Args>
decltype(auto) last(Args&&... args){
return (std::forward<Args>(args), ...);
}

Make a tuple and get the last element:
template<typename... Args>
auto last(Args&&... args)
{
return std::get<sizeof...(Args)-1>(std::forward_as_tuple(args...));
}
Test:
int main()
{
auto&& last_element = last(1, 1.0, true);
static_assert(std::is_same_v<bool, std::remove_cvref_t<decltype(last_element)>>);
}
Demo
C++11 Friendly Demo

As suggested by HolyBlackCat the easiest way to remove this warning is to use an "identity / dummy-function" like this:
template<typename T>
constexpr inline decltype(auto) identityFkt(T&& t)
{
return std::forward<T>(t);
}
It can be used this way:
const auto& last = (identityFkt(std::forward<AParamPack>(aParamPack)), ...);
It results in the same assembly (checked # godbolt) - no overhead (with -O3).
Thank you: #HolyBlackCat

You can use another implementation (it's less efficient, but compiler should be able remove inefficiency here)
template <class T>
decltype(auto) last(T && ... t) { return t; }
template <class ... TT,class T>
decltype(auto) last(T &&,TT && ... tt) { return last( std::forward<TT>(tt)... ); }

Related

Can you invert the order of argument-expansion in an initializer-list?

I am writing a custom interpreted language, which uses a LIFO-stack for data-manipulation. At two places, I need to be able to construct a tuple from values that are stored on the stack. In principle, this code would look like this:
template<typename... Args>
[[nodiscard]] inline std::tuple<Args...> popTupleFromStack(Stack& stack)
{
return { stack.Pop<Args>()... };
}
However, there is a fundamental problem with the LIFO-ordering of the stack: The initializer-list order dictates that calls happen left-to-right, which means that it would actually try to pop the elements in the completely inverse order. Is there any easy way to inverse this order?
I know that fold-expressions allow you to specify left- or right-folds, but it doesn't seem that you can use fold-expressions when you need to initialize an object with the result.
The closes I've come is manually specifying overloadings for the potential number of arguments in the tuple:
template<typename Arg0>
[[nodiscard]] inline std::tuple<Arg0> popStackTuple(Stack& stack)
{
return { stack.Pop<Arg0>() };
}
template<typename Arg0, typename Arg1>
[[nodiscard]] inline std::tuple<Arg0, Arg1> popStackTuple(Stack& stack)
{
Arg1 arg1 = stack.Pop<Arg1>();
Arg0 arg0 = stack.Pop<Arg0>();
return { arg0, arg1 };
}
But this obviously limits the number of arguments I can support, and/or results in a lot of "unnecessary" code. And it seems like such a minor thing not being able to be done with modern C++ (I have everything up to, including C++20 at my disposal if it makes any difference).
You might reverse tuple afterward
template <std::size_t ... Is, typename Tuple>
auto reverse_tuple_impl(std::index_sequence<Is...>, Tuple& tuple)
{
using res_type = std::tuple<std::tuple_element_t<sizeof...(Is) - 1 - Is, std::decay_t<Tuple>>...>;
Is, std::decay_t<Tuple>>>;
return res_type(std::get<sizeof...(Is) - 1 - Is>(tuple)...);
}
template <typename ... Ts>
auto reverse_tuple(std::tuple<Ts...>& tuple)
{
return reverse_tuple_impl(std::index_sequence_for<Ts...>(), tuple);
}
Demo
Non a great improvement but... if you can use C++20, so template lambdas, you can embed the helper function inside reverse_tuple()
template <typename ... Ts>
auto reverse_tuple (std::tuple<Ts...> & tuple)
{
return [&]<std::size_t ... Is> (std::index_sequence<Is...>)
{ return std::make_tuple(std::get<sizeof...(Is)-1u-Is>(tuple)...); }
(std::index_sequence_for<Ts...>{});
}

How do I unwrap a parameter pack of length 1 (containing a single value)?

I am writing a little variadic summing function (using c++20, but my question would remain the same with c++17 syntax). I would like to make the following code as short and clear as possible (but without using folding expressions. This is only a toy problem, but in later applications I would like to avoid fold expressions):
Additive auto sum(Additive auto&& val, Additive auto&&... vals) {
auto add = [](Additive auto&& val1, Additive auto&& val2) {
return val1 + val2;
}; // neccessary??
if constexpr(sizeof...(vals) == 1) {
return add(val, std::forward<decltype(vals)>(vals)...); // (1)
//return val + std::forward<decltype(vals)>(vals)...; // (2)
}
else return val + sum(std::forward<decltype(vals)>(vals)...);
}
Using line (1) the above code compiles, but it makes the definition of the 'add' lambda neccessary. Line (2), however, does not compile, I get the following error with gcc: parameter packs not expanded with ‘...’. If I add parentheses around the std::forward expression in line (2), I get the following error: expected binary operator before ‘)’ token.
Is there any way to pass a parameter pack with length 1 to an operator?
Embrace the power of negative thinking and start induction with zero instead of one:
auto sum(auto &&val, auto &&...vals) {
if constexpr (sizeof...(vals) == 0)
return val;
else
return val + sum(std::forward<decltype(vals)>(vals)...);
}
The above definition has the side effect that sum(x) will now compile and return x. (In fact, you can even make the function work with no arguments, by having it return zero, but then the question arises: zero of which type? To avoid having to go there, I left this case undefined.) If you insist on sum being defined only from arity 2 upwards, you can use this instead:
auto sum(auto &&val0, auto &&val1, auto &&...vals) {
if constexpr (sizeof...(vals) == 0)
return val0 + val1;
else
return val0 + sum(std::forward<decltype(val1)>(val1),
std::forward<decltype(vals)>(vals)...);
}
However, you should probably allow the ‘vacuous’ case whenever it makes sense to do so: it makes for simpler and more general code. Notice for example how in the latter definition the addition operator appears twice: this is effectively duplicating the folding logic between the two cases (in this case it’s just one addition, so it’s relatively simple, but with more complicated operations it might be more burdensome), whereas handling the degenerate case is usually trivial and doesn’t duplicate anything.
(I omitted concept annotations, as they do not seem particularly relevant to the main problem.)
template<class... Additive> decltype(auto) sum(Additive &&...val) {
return (std::forward<Additive>(val) + ...);
}
?
Offtopic: unsure about Op's real needs, I've accidentally quickdesigned one thing I've been thinking of, from time to time. :D
#include <iostream>
#include <functional>
#include <type_traits>
template<class... Fs> struct Overloads;
template<class F, class... Fs> struct Overloads<F, Fs...>: Overloads<Fs...> {
using Fallback = Overloads<Fs...>;
constexpr Overloads(F &&f, Fs &&...fs): Fallback(std::forward<Fs>(fs)...), f(std::forward<F>(f)) {}
template<class... Args> constexpr decltype(auto) operator()(Args &&...args) const {
if constexpr(std::is_invocable_v<F, Args...>) return std::invoke(f, std::forward<Args>(args)...);
else return Fallback::operator()(std::forward<Args>(args)...);
}
private:
F f;
};
template<class... Fs> Overloads(Fs &&...fs) -> Overloads<Fs...>;
template<class F> struct Overloads<F> {
constexpr Overloads(F &&f): f(std::forward<F>(f)) {}
template<class... Args> constexpr decltype(auto) operator()(Args &&...args) const {
return std::invoke(f, std::forward<Args>(args)...);
}
private:
F f;
};
template<> struct Overloads<> {
template<class... Args> constexpr void operator()(Args &&...) const noexcept {}
};
constexpr int f(int x, int y) noexcept { return x + y; }
void g(int x) { std::cout << x << '\n'; }
template<class... Vals> decltype(auto) omg(Vals &&...vals) {
static constexpr auto fg = Overloads(f, g);
return fg(std::forward<Vals>(vals)...);
}
int main() {
omg(omg(40, 2));
}
>_<
You can unpack the one item into a variable and use that:
if constexpr (sizeof...(vals) == 1) {
auto&& only_value(std::forward<decltype(vals)>(vals)...);
return val + only_value;
}

Mimic std::bind_front in c++17 for calling member functions

Is it somehow possible to easily mimic std::bind_front in C++17 ? (just for member function wrapping is fine)
I took a look at implementation in c++20 aiming to copy but it seems its very much implementation specific indeed.
I'm thinking a lambda wrapper or template function/object might work?
(Performance is not an issue here)
This can be a starting point
template<typename F, typename ...FrontArgs>
struct bindfronthelper
{
bindfronthelper(F f, FrontArgs&&...args)
: mF{std::move(f)}
, mFrontArg{std::forward<FrontArgs>(args)...}
{}
template<typename ...BackArgs>
auto operator()(BackArgs&&...args) const
{
return std::apply(mF, std::tuple_cat(mFrontArg, std::forward_as_tuple(args...)));
}
F mF;
std::tuple<std::decay_t<FrontArgs>...> mFrontArg;
};
template<typename F, typename ...FrontArgs>
auto mybindfront(F f, FrontArgs&&...args)
{
return bindfronthelper<F, FrontArgs...>{std::move(f), std::forward<FrontArgs>(args)...};
}
https://godbolt.org/z/Tz9fen
Written quickly and not tested well, so there might be some pitfalls in corner cases. At least it shows how this can be achieved.
Ok I made this over complicated, here is simpler version:
template<typename T, typename ...Args>
auto tuple_append(T&& t, Args&&...args)
{
return std::tuple_cat(
std::forward<T>(t),
std::forward_as_tuple(args...)
);
}
template<typename F, typename ...FrontArgs>
decltype(auto) mybindfront(F&& f, FrontArgs&&...frontArgs)
{
return [f=std::forward<F>(f),
frontArgs = std::make_tuple(std::forward<FrontArgs>(frontArgs)...)]
(auto&&...backArgs)
{
return std::apply(
f,
tuple_append(
frontArgs,
std::forward<decltype(backArgs)>(backArgs)...));
};
}
https://godbolt.org/z/cqPjTY
still passes all test I've provided. I'm keeping old version since with a bit of work it can be tweaked to work with older standard of c++.
One really simpel way I found is with lambda's (in this case capturing this - but you can change that easily to be generally adoptable):
auto bind_m = [this](auto mem_f) {
auto wrapper = [=] (auto&&... args) {return std::mem_fn(mem_f)(this, std::forward<decltype(args)>(args)...);};
return wrapper;
};
The lambda creates another lambda and returns it.
template<typename F, typename... FRONT_ARGS>
auto bind_front(F&& f, FRONT_ARGS&&... front_args)
{
// front_args are copied because multiple invocations of this closure are possible
return [captured_f = std::forward<F>(f), front_args...](auto&&... back_args) {
return std::invoke(captured_f, front_args...,
std::forward<decltype(back_args)>(back_args)...);
};
}

Triggering void constexpr at compile time?

I have a constexpr function that groups many static_asserts for design contracts. I would like to call it at compile time, without having to create an unused constexpr variable.
Here is an example of what I currently have to do (c++17).
template<size_t N = 0, typename... Ts, typename F>
inline constexpr int tuple_for(const std::tuple<Ts...>& t, const F& func) {
func(std::get<N>(t));
if constexpr(N < sizeof...(Ts) - 1) {
return tuple_for<N + 1, Ts...>(t, func);
} else {
return 0;
}
}
auto do_checks = [](const auto& t) {
static_assert(has_some_method_v<decltype(t)>,
"You need some_method");
return 0;
}
[[maybe_unused]]
constexpr int i_am_sad = tuple_for(my_tuple, do_checks);
Is there any other way to achieve this behaviour? Maybe something new in c++17?
Thank you.
edit:
Note that as these checks are to be generalized, I believe having the asserts in a function is the right way to go here.
You might use it in other constexpr context as static_assert:
static_assert((static_cast<void>(tuple_for(my_tuple, do_checks)), true), "!");
[Note]: the cast to void is to generalize, if you want to return class with evil overloaded comma.
static_assert is a declaration-statement, so you can just plonk it in free space.
No need for a function.
This is precisely the use case for that. :)

Unexpected result when trying to compose a curried lambda with another lambda

I am toying with C++11 lambdas and was trying to mimick some function from the functional module of the D programming language. I was actually trying to implement curry and compose. Here is the main that I am trying to get working:
int main()
{
auto add = [](int a, int b)
{
return a + b;
};
auto add5 = curry(add, 5);
auto composed = compose(add5, add);
// Expected result: 25
std::cout << composed(5, 15) << std::endl;
}
The problem is that I don't get the same result from g++ and clang++. I get:
35 with g++ 4.8.1
25 with g++ 4.8.2
25 with g++ 4.9
32787 with clang++ 3.5 (trunk used with Coliru)
g++ 4.8.2 and 4.9 give me the expected result. The results obtained from g++ 4.8.1 and clang 3.5 do not depend on the value passed to curry. I first thought that this may be a compiler bug, but it is more likely that I have an error in my code.
Here is my implementation of curry:
template<typename Function, typename First, std::size_t... Ind>
auto curry_impl(const Function& func, First&& first, indices<Ind...>)
-> std::function<
typename function_traits<Function>::result_type(
typename function_traits<Function>::template argument_type<Ind>...)>
{
return [&](typename function_traits<Function>::template argument_type<Ind>&&... args)
{
return func(
std::forward<First>(first),
std::forward<typename function_traits<Function>::template argument_type<Ind>>(args)...
);
};
}
template<typename Function, typename First,
typename Indices=indices_range<1, function_traits<Function>::arity>>
auto curry(Function&& func, First first)
-> decltype(curry_impl(std::forward<Function>(func), std::forward<First>(first), Indices()))
{
using FirstArg = typename function_traits<Function>::template argument_type<0>;
static_assert(std::is_convertible<First, FirstArg>::value,
"the value to be tied should be convertible to the type of the function's first parameter");
return curry_impl(std::forward<Function>(func), std::forward<First>(first), Indices());
}
And here is my implementation of compose (note that I only wrote a binary compose while the D one is variadic):
template<typename First, typename Second, std::size_t... Ind>
auto compose_impl(const First& first, const Second& second, indices<Ind...>)
-> std::function<
typename function_traits<First>::result_type(
typename function_traits<Second>::template argument_type<Ind>...)>
{
return [&](typename function_traits<Second>::template argument_type<Ind>&&... args)
{
return first(second(
std::forward<typename function_traits<Second>::template argument_type<Ind>>(args)...
));
};
}
template<typename First, typename Second,
typename Indices=make_indices<function_traits<Second>::arity>>
auto compose(First&& first, Second&& second)
-> decltype(compose_impl(std::forward<First>(first), std::forward<Second>(second), Indices()))
{
static_assert(function_traits<First>::arity == 1u,
"all the functions passed to compose, except the last one, must take exactly one parameter");
using Ret = typename function_traits<Second>::result_type;
using FirstArg = typename function_traits<First>::template argument_type<0>;
static_assert(std::is_convertible<Ret, FirstArg>::value,
"incompatible return types in compose");
return compose_impl(std::forward<First>(first), std::forward<Second>(second), Indices());
}
The class function_trait is used to get the arity, the return type and the type of the arguments of a lambda. This code heavily relies on the indices trick. Since I don't use C++14, I don't use std::index_sequence but an older implementation under the name indices. indices_range<begin, end> is an indices sequence corresponding to the range [begin, end). You can find the implementation of these helper metafunctions (as well as curry and compose) on the online version of the code, but they are less meaningful in this problem.
Do I have a bug in the implementation of curry and/or compose or are the bad results (with g++ 4.8.1 and clang++ 3.5) due to compiler bugs?
EDIT: You may find the code above not quite readable. So, here are versions of curry and compose that are exactly the same, but use alias templates to reduce the boilerplate. I also removed the static_asserts; while they may be helpful information, that's just too much text for the question and they do not play a part in the problem at hand.
template<typename Function, typename First, std::size_t... Ind>
auto curry_impl(const Function& func, First&& first, indices<Ind...>)
-> std::function<
result_type<Function>(
argument_type<Function, Ind>...)>
{
return [&](argument_type<Function, Ind>&&... args)
{
return func(
std::forward<First>(first),
std::forward<argument_type<Function, Ind>>(args)...
);
};
}
template<typename Function, typename First,
typename Indices=indices_range<1, function_traits<Function>::arity>>
auto curry(Function&& func, First first)
-> decltype(curry_impl(std::forward<Function>(func), std::forward<First>(first), Indices()))
{
return curry_impl(std::forward<Function>(func), std::forward<First>(first), Indices());
}
template<typename First, typename Second, std::size_t... Ind>
auto compose_impl(const First& first, const Second& second, indices<Ind...>)
-> std::function<
typename result_type<First>(
typename argument_type<Second, Ind>...)>
{
return [&](argument_type<Second, Ind>&&... args)
{
return first(second(
std::forward<argument_type<Second, Ind>>(args)...
));
};
}
template<typename First, typename Second,
typename Indices=make_indices<function_traits<Second>::arity>>
auto compose(First&& first, Second&& second)
-> decltype(compose_impl(std::forward<First>(first), std::forward<Second>(second), Indices()))
{
return compose_impl(std::forward<First>(first), std::forward<Second>(second), Indices());
}
As I believe others have mentioned in your comments, the issues relating to your code are lifetime issues. Note that you're passing the second parameter, 5, to curry as an rvalue:
auto add5 = curry(add, 5);
Then, in the invocation of the curry function, you're creating a copy of that variable on the stack as one of the parameters:
auto curry(Function&& func, First first)
Then, in your call to curry_impl you pass a reference to the first that won't exist once your call to curry completes. As the lambda you're producing uses a reference to a variable that no longer exists, you get undefined behavior.
To fix the problem you're experiencing, simply change the prototype of curry to use a universal reference to first and make sure you don't pass rvalues to curry:
template<typename Function, typename First,
typename Indices=indices_range<1, function_traits<Function>::arity>>
auto curry(Function&& func, First&& first)
-> decltype(curry_impl(std::forward<Function>(func), std::forward<First>(first), Indices()))
{
using FirstArg = typename function_traits<Function>::template argument_type<0>;
static_assert(std::is_convertible<First, FirstArg>::value,
"the value to be tied should be convertible to the type of the function's first parameter");
return curry_impl(std::forward<Function>(func), std::forward<First>(first), Indices());
}
Then in main:
int foo = 5;
auto add5 = curry(add, foo);
Of course, limiting yourself to lvalue expressions is a pretty huge problem with the interface, so it's worth mentioning that if you planned on utilizing this outside of an exercise, it would be a good idea to provide an interface where rvalues can be used.
Then again, I would change it so that the resulting functor owns copies of its components as std::bind does. I know I would be a little perplexed if the following code didn't work:
std::function<int(int)> foo()
{
std::function<int(int, int)> add = [](int a, int b)
{
return a + b;
};
return curry(add, 5);
}
Edit: I see now that some versions of gcc still require the values to be captured by value into the resulting lamba. GCC 4.9.0 20131229 is the build I tested it on which works fine.
Edit #2: specified correct usage per Xeo