I'm currently in the process of writing arithmetic operator overloads for tuples. The operator iterates over the tuple to perform the operation on each of its individual element. Here is the definition for operator +=:
template< typename... Ts, std::size_t I = 0 >
inline typename std::enable_if< I == sizeof... (Ts), std::tuple< Ts... >& >::type operator +=(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
return lhs;
}
template< typename... Ts, std::size_t I = 0 >
inline typename std::enable_if< I != sizeof... (Ts), std::tuple< Ts... >& >::type operator +=(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
std::get< I >(lhs) += std::get< I >(rhs);
return operator +=< Ts..., I + 1 >(lhs, rhs);
}
Unfortunately, when I attempt to call the operator, GCC 4.6 cannot decide which overload it should use. For example:
std::tuple< int, int, int, int > a = std::make_tuple(1, 2, 3, 4), b = std::make_tuple(5, 6, 7, 8);
a += b;
Yields the following error:
:/Workspace/raster/main.cpp:833:7: instantiated from here
C:/Workspace/raster/main.cpp:809:45: error: no matching function for call to 'operator+=(std::tuple<int, int, int, int>&, const std::tuple<int, int, int, int>&)'
C:/Workspace/raster/main.cpp:809:45: note: candidates are:
C:/Workspace/raster/main.cpp:800:151: note: template<class ... Ts, unsigned int I> typename std::enable_if<(I == sizeof (Ts ...)), std::tuple<_TElements ...>&>::type operator+=(std::tuple<_TElements ...>&, const std::tuple<_TElements ...>&)
C:/Workspace/raster/main.cpp:806:83: note: template<class ... Ts, unsigned int I> typename std::enable_if<(I != sizeof (Ts ...)), std::tuple<_TElements ...>&>::type operator+=(std::tuple<_TElements ...>&, const std::tuple<_TElements ...>&)
Which is strange since the std::enable_if
condition should reject the inappropriate call. For now, I have the following workaround which was actually my prior implementation. The above version is in fact a simplification attempt.
template< std::size_t I, typename... Ts >
inline typename std::enable_if< I == sizeof... (Ts), std::tuple< Ts... >& >::type assignadd_impl(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
return lhs;
}
template< std::size_t I, typename... Ts >
inline typename std::enable_if< I != sizeof... (Ts), std::tuple< Ts... >& >::type assignadd_impl(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
std::get< I >(lhs) += std::get< I >(rhs);
return assignadd_impl< I + 1, Ts... >(lhs, rhs);
}
template< typename... Ts >
inline std::tuple< Ts... >& operator +=(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
return assignadd_impl< 0, Ts... >(lhs, rhs);
}
This compiles and works as expected. Why does the simplified version refuse to compile? Thanks.
We can iterate over tuples using a simple for-loop. We can do common sequence operations on tuples like indexing, slicing, concatenation, multiplication, getting the min, max value and so on.
A C++ tuple is a container that can store multiple values of multiple types in it. We can access the elements of the tuple using std::get(), but std::get() always takes a constant variable parameter, so we can not simply iterate through it using a loop.
Using explicitly specified template arguments to a function or class template requires that any template parameter packs appear at the end of the overall template parameter list. Moving Ts...
to the end of the template parameter lists and changing the calls appropriately makes the code work. Section 14.8.2.1 of the current C++0x draft states that parameter packs that are not at the end of the template parameter list cannot be deduced from a function call (which makes your original code fail), but explicitly specifying all of the template arguments to operator+=
in all cases still causes a SFINAE error. A previous question has a link to the exact text forbidding it; IBM's documentation says that it is an error as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With