【发布时间】:2017-11-09 19:04:48
【问题描述】:
我正在尝试编写模板函数/运算符,例如+,用于在两个相同类型的元组之间进行算术运算。例如,对于
std::tuple<int,double> t = std::make_tuple(1,2);
我想做
auto t1 = t + t;
逻辑很简单:按元素进行算术运算。但我不知道如何在 c++ 模板编程(c++11/17)中进行这项工作。我下面的代码不能用g++ -std=c++11 tuple_arith.cpp 编译。特别是,我想不出让通用 add 函数 (template<typename T> T add(T x, T y) { return x + y; }) 与元组操作代码一起工作的正确方法。
谁能帮忙解释一下如何解决这个问题?
#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;
}
具体错误有:
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
}
^
-- 更新--
感谢您迄今为止提供的有用答案。是否可以使其适用于任何 Operator Wrappers,例如std::{plus,minus,multiplies,divides}?这就是我试图通过模板参数typename _opT 实现的目标。最后,我正在寻找一个可以将兼容的运算符作为参数的函数/对象。
【问题讨论】:
-
将自己的函数注入
namespace std是违法的。标识符以__或_开头后跟大写字母是非法的。这些不是您的代码无法工作的原因,大多数编译器不会要求您这样做,但您也不应该这样做。 -
只是:ideone.com/giSbxM 有什么问题?
-
@gurka Ostensibly OP 正在寻找一种解决方案,可以优雅地扩展到具有多于或少于两个元素的
tuples。 -
除非可能没有放在命名空间std中。但是,在某些情况下是允许的:en.cppreference.com/w/cpp/language/extending_std
-
@Yakk -- 它的名称包含两个连续的下划线,而不仅仅是以两个连续的下划线开头。 (另外,正如您所说,以下划线后跟大写字母的名称)
标签: c++ c++11 variadic-templates c++17 stdtuple