I'm trying to write template functions/operators such as +
for doing arithmetic operations between two tuples of the same type. For example, for
std::tuple<int,double> t = std::make_tuple(1,2);
I'd like to do
auto t1 = t + t;
The logic is simple: to do the arithmetic element-wise. But I can't figure out how to make this work in c++ template programming (c++11/17). My code below doesn't compile with g++ -std=c++11 tuple_arith.cpp
. In particular, I can't figure out the right way of getting the generic add
function (template<typename T> T add(T x, T y) { return x + y; }
) to work with the tuple manipulating code.
Can someone help explain how to fix the issue?
#include <tuple>
namespace std {
template<typename _Tp, size_t __i, size_t __size, typename _opT >
struct __tuple_arith {
static constexpr _Tp __op(const _Tp& __t, const _Tp& __u, const _opT& op) {
return std::tuple_cat(std::make_tuple(op(std::get<__i>(__t), std::get<__i>(__u))
, __tuple_arith<_Tp, __i + 1, __size, _opT>::__op(__t, __u)));
}
};
template<typename _Tp, size_t __size, typename _opT>
struct __tuple_arith<_Tp, __size, __size - 1, _opT> {
static constexpr _Tp __op(const _Tp& __t, const _Tp& __u, const _opT& op) {
return std::make_tuple(op(std::get<__size-1>(__t), std::get<__size -1>(__u)));
}
};
template<typename T> T add(T x, T y) { return x + y; }
template<typename... _TElements> constexpr tuple<_TElements...>
operator+(const tuple<_TElements...>& __t, const tuple<_TElements...>& __u) {
using op = __tuple_arith<tuple<_TElements...>, 0, sizeof...(_TElements), decltype(add)>;
return op::__op(__t, __u, add);
}
}; //namespace std
#include <iostream>
using namespace std;
int main() {
std::tuple<int,double> t = std::make_tuple(1,2);
auto t1 = t + t;
cout << std::get<0>(t1) << std::endl;
return 0;
}
The specific errors are:
tuple_arith.cpp:14:10: error: template argument ‘(__size - 1)’ involves template parameter(s)
struct __tuple_arith<_Tp, __size, __size - 1, _opT> {
^
tuple_arith.cpp: In function ‘constexpr std::tuple<_Elements ...> std::operator+(const std::tuple<_Elements ...>&, const std::tuple<_Elements ...>&)’:
tuple_arith.cpp:24:90: error: decltype cannot resolve address of overloaded function
__tuple_arith<tuple<_TElements...>, 0, sizeof...(_TElements), decltype(add)>;
^
tuple_arith.cpp:24:91: error: template argument 4 is invalid
__tuple_arith<tuple<_TElements...>, 0, sizeof...(_TElements), decltype(add)>;
^
tuple_arith.cpp:25:12: error: ‘op’ has not been declared
return op::__op(__t, __u, add);
^
tuple_arith.cpp: In instantiation of ‘constexpr std::tuple<_Elements ...> std::operator+(const std::tuple<_Elements ...>&, const std::tuple<_Elements ...>&) [with _TElements = {int, double}]’:
tuple_arith.cpp:34:17: required from here
tuple_arith.cpp:26:3: error: body of constexpr function ‘constexpr std::tuple<_Elements ...> std::operator+(const std::tuple<_Elements ...>&, const std::tuple<_Elements ...>&) [with _TElements = {int, double}]’ not a return-statement
}
^
-- Update --
Thanks for the helpful answers so far. Is it possible to make it work for any Operator Wrappers, e.g. std::{plus,minus,multiplies,divides}
? That's what I was trying to achieve with the template parameter typename _opT
. In the end, I'm looking for a function/object that can take a compatible Operator as a parameter.