I would like to split a parameter pack into the first N - 1 and the Nth parameters without using the typical index_sequence & tuple trick but cannot seem to wrap my head around it, yet I'm pretty sure it should be doable? (getting the last item is easy enough with recursion).
The final function to call looks like
void Fun( Foo a, Bar b );
and a is acquired from a variadic one in turn:
template< class... T >
Foo CalcFoo( T... args );
My current implementation:
//get the last item of the pack
template< class T >
T split_last( T t ){ return t; }
template< class... T >
T split_last( T, T... t ){ return split_last( t... ); }
//helper
template< class... T, size_t... Indices >
Foo CalcFoo( const std::tuple< T... >& args, index_sequence< Indices... > )
{
return CalcFoo( std::get< Indices >( args )... );
}
//split and call
template< class... T >
void MoreFun( T... args )
{
//make a tuple containing all, then get n -1 items out of it
const auto tup = std::make_tuple< T... >( args... );
Fun( CalcFoo( tup, make_index_sequence< sizeof...( T ) - 1 >() ),
split_last( args... ) );
}
update apart from wanting to know how to do this without a tuple just for the sake of it I also asked this because I somehow thought maybe a tuple would cause overhead. Thereby ignoring the premature optimization mantra, which, as usual, turned out to be correct once again. Compiled in release mode with VS2013 both my and Horstling's code yield the exact same assembly code. Everything including CalcFoo is inlined up until the call to Fun. In other words: the tuple is completely gone. So I'll probably stick with this implementation anyway because it's pretty clear.
Ok, let's be creative. I`m sure there is a more "standard" way to do this, but I kinda like this solution ;)
http://coliru.stacked-crooked.com/a/25a3fa276e56cd94
The core idea is to recursively rotate the arguments until we can split out the (formerly) last argument.
template <size_t N>
struct MoreFunHelper
{
template <class Head, class... Tail>
static void RotateLeft(Head head, Tail... tail)
{
MoreFunHelper<N - 1>::RotateLeft(tail..., head);
}
};
template <>
struct MoreFunHelper<0>
{
template <class Head, class... Tail>
static void RotateLeft(Head head, Tail... tail)
{
Fun(CalcFoo(tail...), head);
}
};
template< class... T >
void MoreFun(T... args)
{
MoreFunHelper<sizeof...(T) - 1>::RotateLeft(args...);
}
So if we start with the arguments
1 2 3 4 5
it rotates them 4 times:
2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4
Now we can split them smoothly into [5] and [1 2 3 4], which is exactly what we want. At this point, the recursion stops and just calls the functions CalcFoo and Fun.
Related
I'm trying to write a function that creates a new std::tuple from an existing one, with skipping the element on a given index. In example:
I have a tuple t defined as below:
constexpr auto t = std::tuple(1, 2, 3, 4);
And I want to copy it to another tuple. However, I want to skip the nth element. Let's say that in this case, the nth element I want to skip is 3 (this would mean that I want to skip the element with the index 2). This would result in a new tuple defined as:
std::tuple(1, 2, 4);
This is the closest I got until now:
template<std::size_t N, typename T, std::size_t ... is>
constexpr auto fun(T&& tp, std::index_sequence<is...>&& i) noexcept {
return std::tuple((is != N ? std::get<is>(tp) : 0) ...);
}
template<std::size_t N, std::size_t... elems>
constexpr auto fun2() noexcept {
constexpr auto t = std::tuple(elems...);
return fun<N>(std::forward_as_tuple(elems...), std::make_index_sequence<sizeof...(elems)>());
}
However, instead of removing the nth element, I set it to 0.
Ideally, I would change the return argument in the function fun() to create a new tuple using multiple temporary tuples:
return std::tuple_cat((is != N ? std::tuple(std::get<is>(tp)) : std::tuple()) ...);
However, the issue with this is that the ternary operator has to have matching types on both sides.
Another approach I tried was based on recursion:
template<std::size_t N, std::size_t head, std::size_t... tail>
constexpr auto fun3() noexcept {
if constexpr(!sizeof...(tail))
return std::tuple(head);
if constexpr(sizeof...(tail) - 1 == N)
return std::tuple_cat(fun3<N, tail...>());
if constexpr(sizeof...(tail) - 1 != N)
return std::tuple_cat(std::tuple(head), fun3<N, tail...>());
}
However, that was even more unsuccessful. In this case, if N is equal to 0, the nth element (which is the first element here as well) will still be used in the new tuple. Also, this won't even compile, because there's an issue with the second statement:
if constexpr(sizeof...(tail) - 1 == N)
What am I missing here? How can I copy a tuple and skip one of its elements during the copy?
I'm using C++17, and I need the function to be evaluated during compile-time.
What about
return std::tuple_cat( foo<is, N>::func(std::get<is>(tp)) ...);
where foo is a struct with specialization as follows?
template <std::size_t, std::size_t>
struct foo
{
template <typename T>
static auto func (T const & t)
{ return std::make_tuple(t); }
}
template <std::size_t N>
struct foo<N, N>
{
template <typename T>
static std::tuple<> func (T const &)
{ return {}; }
}
(caution: code not tested).
This is almost your ternary operator idea but without the problem of matching the types in both sides: only the right type is instantiated.
Another solution would be to create two index sequences that refer to the before and after parts of the tuple.
template<std::size_t nth, std::size_t... Head, std::size_t... Tail, typename... Types>
constexpr auto remove_nth_element_impl(std::index_sequence<Head...>, std::index_sequence<Tail...>, std::tuple<Types...> const& tup) {
return std::tuple{
std::get<Head>(tup)...,
// We +1 to refer one element after the one removed
std::get<Tail + nth + 1>(tup)...
};
}
template<std::size_t nth, typename... Types>
constexpr auto remove_nth_element(std::tuple<Types...> const& tup) {
return remove_nth_element_impl<nth>(
std::make_index_sequence<nth>(), // We -1 to drop one element
std::make_index_sequence<sizeof...(Types) - nth - 1>(),
tup
);
}
Here's a test for this function:
int main() {
constexpr auto tup = std::tuple{1, 1.2, 'c'};
constexpr auto tup2 = remove_nth_element<0>(tup);
constexpr auto tup3 = remove_nth_element<2>(tup);
static_assert(std::is_same_v<decltype(tup2), const std::tuple<double, char>>);
static_assert(std::is_same_v<decltype(tup3), const std::tuple<int, double>>);
return 0;
}
Live example
This solution has the advantages of not constructing intermediary tuples and not using std::tuple_cat, which both can be hard on compile times.
Just a few minutes after posting the question, I found a workaround. It's not ideal, but hey:
template<std::size_t N, typename T, std::size_t ... is>
constexpr auto fun(T&& tp, std::index_sequence<is...>&& i) noexcept {
return std::tuple((is < N ? std::get<is>(tp) : std::get<is+1>(tp)) ...);
}
template<std::size_t N, std::size_t... elems>
constexpr auto fun2() noexcept {
constexpr auto t = std::tuple(elems...);
return fun<N>(std::forward_as_tuple(elems...), std::make_index_sequence<sizeof... (elems) - 1>());
}
This way, we copy all of the elements prior to the nth element, and when we reach the nth element, we increase every next index for 1. We won't go out of range, since we pass the index_sequence that has 1 element less than the tuple that is passed.
I hope that this answer helps someone.
I was reading this note on the implementation of symmetric operators in Boost.Operator https://www.boost.org/doc/libs/1_69_0/libs/utility/operators.htm#symmetry and I suspect it is awfully outdated.
The discussion revolves on what is the best way to implement operator+ generically, if a consistent operator+= is available. The conclusion there is that it is (was),
T operator+( const T& lhs, const T& rhs ){
T nrv( lhs ); nrv += rhs; return nrv;
}
because at the time some compilers supported NRVO, as opposed to RVO.
Now, with NRVO being mandatory, and all sorts of optimization being performed, is this still the case?
For example other version that may make sense now for certain cases is:
T operator+(T lhs, const T& rhs ){
T ret(std::move(lhs)); ret += rhs; return ret;
}
or
T operator+(T lhs, const T& rhs ){
lhs += rhs; return lhs;
}
Given a class that has a constructor, a move constructor, and reasonable operator+=. For example:
#include<array>
#include<algorithm>
using element = double; // here double, but can be more complicated
using array = std::array<double, 9>; // here array, but can be more complicated
array& operator+=(array& a, array const& b){
std::transform(begin(a), end(a), begin(b), begin(a), [](auto&& x, auto&& y){return x + y;});
return a;
}
array& operator+=(array&& a, array const& b){
std::transform(begin(a), end(a), begin(b), begin(a), [](auto&& x, auto&& y){return x + std::move(y);});
return a;
}
What is the best way to implement a symmetric operator+? Here is a set of possible codes
/*1*/ array sum(array const& a, array const& b){array tmp(a); tmp+=b; return tmp;} // need operator+= and copy-constructor
/*2*/ array sum(array const& a, array const& b){return array(a)+=b;} // needs operator+= && and copy-constructor
/*3*/ array sum(array a, array const& b){return std::move(a)+=b;} // needs operator+= && and can use move-constructor
/*4*/ array sum(array a, array const& b){array tmp(std::move(a)); tmp+=b; return tmp;} // needs operator+= and can use move-constructor
I tried it in https://godbolt.org/z/2YPhcg and just by counting the number of assembly lines, which all other things being equal might tell what is the best implementation. I get these mixed results:
| code | gcc -O2 | clang -O2 |
|:-----------|------------:|:------------:|
| /*1*/ | 33 lines | 64 lines |
| /*2*/ | 39 lines | 59 lines |
| /*3*/ | 33 lines | 62 lines |
| /*4*/ | 33 lines | 64 lines |
While /*3*/ and /*4*/ can benefit from calls of the form sum(std::move(a), b) or even sum(sum(a, c), b).
So is T tmp(a); tmp+=b; return tmp; still the best way to implement operator+(T [const&], T const&)?
It looks like if there is a move constructor and a moving +=, there are other possibilities but only seem to produce simpler assembly in clang.
If the signature is:
T operator+(T const& a, T const& b )
(as you say in the bolded question text), then the body should be:
return T(a) += b;
where the result object is the only T constructed. The version T nrv( lhs ); nrv += rhs; return nrv; theoretically risks the compiler not merging nrv with the result object.
Note that the above signature does not allow moving out of any of the arguments. If it's desirable to move out of the lhs, then this seems optimal to me:
T operator+(T const& a, T const& b)
{
return T(a) += b;
}
T operator+(T&& a, T const& b)
{
return T(std::move(a)) += b;
}
In both cases the result object is guaranteed to be the only object constructed. In the "classic" version taking T a, then the case of an rvalue argument would incur an extra move.
If you want to move out of the right-hand side then two more overloads can be added :)
Note that I have not considered the case of returning T&& for reasons described here
I had a look at this archive post
Implementing std::rank for other containers
But it is still unclear to me how the logic of std::rank implementation works.
When I refer to the following
std::rank
I see the following under Possible Implementation
template<class T>
struct rank : public std::integral_constant<std::size_t, 0> {};
template<class T>
struct rank<T[]> : public std::integral_constant<std::size_t, rank<T>::value + 1> {};
template<class T, std::size_t N>
struct rank<T[N]> : public std::integral_constant<std::size_t, rank<T>::value + 1> {};
Could anyone provide a simple explanation about how the above implementation logic works? (does it use variadic templates at all?)
I'll try to explain in a simple way.
With std::rank you want to know the number of dimensions of an array type where a not-array is considered an array of zero dimensions.
Given a type T, you have three cases:
T isn't an array
T is an "array of unknown bound" (see in this page) of elements of another type U, that is an array of unknown size, and we can express is as U[], where U is the other type
T is an array on known size N of elements of type U and we can express it as U[N], where U is the other type.
In cases 2 and 3 the sub-type U can be an array or not, so the game restart.
Look at the "possible implementation" that I have rewritten using U instead of T in cases 2 and 3
// case 1: T isn't an array
template<class T>
struct rank
: public std::integral_constant<std::size_t, 0>
{ };
// case 2: T is an array of unknown bound (U[])
template<class U>
struct rank<U[]>
: public std::integral_constant<std::size_t, rank<U>::value + 1>
{ };
// case 3: T is an array on size N (U[N])
template<class U, std::size_t N>
struct rank<U[N]>
: public std::integral_constant<std::size_t, rank<U>::value + 1>
{ };
When you ask for std::rank<T>::value when a not-array type T, the only version of rank that matches is the first one, so the value is zero (inherited from std::integral_constant<std::size_t, 0>).
Instead, when you ask for std::rank<T>::value when T is an array type (suppose T is int[3], so U is int and N is 3) there are two version of rank that match std::rank<T>: the first one (the main, not specialized) and one of the two partial specializations). But the rules of C++ impose the compiler to choose the most specialized version, so is chose the specialized version (the third version, in case of int[3]) that add 1 at std::rank<U>::value.
A practical example
std::rank<int[1][2][3]>::value
== 1 + std::rank<int[1][2]>::value
== 1 + 1 + std::rank<int[1]>::value
== 1 + 1 + 1 + std::rank<int>::value
== 1 + 1 + 1 + 0
== 3
I wonder why this choice is made. It would allow to write many functions in a very clear and neat way.. for instance:
int greatestCommonDivisor(int a, int b)
{
if (b > a)
std::tie(a, b) = { b, a };
while (b > 0)
std::tie(a, b) = { b, a % b };
return a;
}
std::initializer_list is a homogeneous collection of items, while std::tuple is heterogeneous. The only case where it makes sense to define a std::tuple::operator= for std::initializer_list is when the tuple is homogeneous and has the same size as the initializer list, which is a rare occurrence.
(Additional information in this question.)
Solution/workaround: you can use std::make_tuple instead:
int greatestCommonDivisor(int a, int b)
{
if (b > a)
std::tie(a, b) = std::make_tuple(b, a);
while (b > 0)
std::tie(a, b) = std::make_tuple(b, a % b);
return a;
}
...or std::tuple's constructor in C++17 (thanks to Template argument deduction for class templates):
int greatestCommonDivisor(int a, int b)
{
if (b > a)
std::tie(a, b) = std::tuple{b, a};
while (b > 0)
std::tie(a, b) = std::tuple{b, a % b};
return a;
}
Why does
std::tie(a,b) = {b, a};
not compile?
{} on the right hand side of an assignment can only call a non-explicit constructor of an argument of operator=.
The operator= overloads available are:
tuple& operator=( const tuple& other );
tuple& operator=( tuple&& other );
template< class... UTypes >
tuple& operator=( const tuple<UTypes...>& other );
template< class... UTypes >
tuple& operator=( tuple<UTypes...>&& other );
template< class U1, class U2 >
tuple& operator=( const pair<U1,U2>& p );
template< class U1, class U2 >
tuple& operator=( pair<U1,U2>&& p );
The template operator overloads cannot deduce their types from {} (note: this may change in C++17), leaving:
tuple& operator=( const tuple& other );
tuple& operator=( tuple&& other );
where tuple is std::tuple<int&, int&> in this case.
The tuple constructor for tuple<Ts...> that perfect forwards element-wise construction is explicit (#3 on that list). {} will not call an explicit constructor.
The conditionally non-explicit constructor takes Ts const&...; it does not exist if the Ts are non-copyable, and int& is non-copyable.
So there are no viable types to construct from {int&, int&}, and overload resolution fails.
Why does the standard not fix this? Well, we can do it ourselves!
In order to fix this, we'd have to add a special (Ts...) non-explicit constructor to tuple that only exists if the Ts types are all references.
If we write a toy tuple:
struct toy {
std::tuple<int&, int&> data;
toy( int& a, int& b ):data(a,b) {} // note, non-explicit!
};
toy toy_tie( int& a, int& b ) { return {a,b}; }
and use it, you'll notice that
std::tie(a, b) = {b, a};
compiles and runs.
However,
std::tie(a, b) = { b, a % b };
does not, as a%b cannot be bound to int&.
We can then augment toy with:
template<class...>
toy& operator=( std::tuple<int, int> o ) {
data = o;
return *this;
}
(+ defaulted special member functions. template<class...> ensures it has lower priority than the special member functions, as it should).
This which lets assign-from {int,int}. We then run it and... get the wrong result. The gcd of 5,20 is 20. What went wrong?
toy_tie(a, b) = std::tie( b, a );
with both a and b bound to references is not safe code, and that is what
toy_tie(a, b) = { b, a };
does.
In short, doing this right is tricky. In this case, you need to take a copy of the right hand side before assigning to be safe. Knowing when to take a copy and when not to is also tricky.
Having this work implicitly looks error prone. So it is, in a sense, accidental that it doesn't work, but fixing it (while possible) looks like a bad idea.
live example.
I have a std::vector<std::string> v; (initialized). How can I use the range-for loop for accessing all elements except the first one (on index zero). For all elements:
for (const string & s: v)
process(s);
Instead of the v a range expression can be used. How can I write the range expression to skip the first element (or skip the first n elements)?
I know how to get the effect using v.begin() + 1 and using the classic loop. I am searching for the new, more readable, recommended alternative to do that. Possibly something similar to Python slicing? ...like:
for s in v[1:]:
process(s)
Until ranges make it into the standard library, you won't get any better than a vanilla for loop in plain C++ :
for(auto i = begin(v) + 1, e = end(v); i !=e; ++i)
// Do something with *i
Create a wrapper for which begin() and end() return the correct iterators and then you can use that as the second argument.
#include <iostream>
#include <vector>
template< typename Collection >
class FromNth
{
Collection& coll_;
size_t offset_;
public:
FromNth( Collection& coll, size_t offset )
: coll_( coll ), offset_( offset )
{
}
// will nicely resolve to const_iterator if necessary
auto begin() const -> decltype( coll_.begin() )
{ return coll_.begin() + offset_; }
auto end() const -> decltype( coll_.end() )
{ return coll_.end(); }
};
template< typename Collection >
FromNth<Collection> makeFromNth( Collection& collection, size_t offset )
{
return FromNth<Collection>( collection, offset );
}
template< typename Collection >
auto begin( const FromNth<Collection> & wrapper ) -> decltype( wrapper.begin() )
{
return wrapper.begin();
}
template< typename Collection >
auto end( const FromNth<Collection> & wrapper ) -> decltype( wrapper.end() )
{
return wrapper.end();
}
int main()
{
std::vector< int > coll { 2, 3, 5, 7, 11, 13, 17, 19, 23 };
for( auto x : makeFromNth( coll, 1 ) )
{
std::cout << x << '\n';
}
return 0;
}
Note that my fromNth "begin" is undefined behaviour if the size of the input is less than the offset. (If it's equal then it's well defined and begin == end). Therefore do a size check first.
Note: if you are using a recent enough version of boost then iterator_range may already provide you such a "collection" that is similar to my "FromNth".
for( auto const& s : boost::make_iterator_range( v.begin() + 1, v.end() ) )
{
process( s );
}
Note: the code above worked on CodingGround using C++11 GNU 4.8.3. (That site is very slow though). From C++14 you will not need the ->decltype statements (which are needed in C++11 for templates).
Output:
sh-4.3$ g++ -std=c++11 -o main *.cpp
sh-4.3$ main
3
5
7
11
13
17
19
23