我目前正在开发一个使用表达式模板的数值库。不幸的是,我遇到了运算符重载问题。考虑以下精简示例。
#include <vector>
namespace test {
class test {};
template<class A, class B>
class testExpr {};
template<class A, class B>
testExpr<A, B>
operator-(A a, B b)
{
return testExpr<A, B>();
}
}
test::test
stuff(std::vector<test::test> &v)
{ return v.back(); }
int main()
{ }
在使用 gcc 4.4.3 或 clang 2.8 编译时出现以下错误消息:
In file included from eir_test.cc:2:
In file included from /usr/include/c++/4.4/vector:64:
/usr/include/c++/4.4/bits/stl_vector.h:696:16: error: indirection requires pointer operand
('testExpr<__gnu_cxx::__normal_iterator<test::test *, std::vector<test::test, std::allocator<test::test> > >, int>' invalid)
{ return *(end() - 1); }
^~~~~~~~~~~~
eir_test.cc:21:12: note: in instantiation of member function 'std::vector<test::test, std::allocator<test::test> >::back' requested here
return v.back();
^
1 error generated.
出于某种原因,编译器会查找测试 namespace 并找到我的通用运算符。我将这种形式与一些特性魔法结合使用,以减少我必须为运算符(operator)制作的版本数量。它应该接受 4 种不同的数据类型(包括 double 和 int),这会导致很多不同的组合。
有什么方法可以在不为每个运算符拼出所有组合的情况下完成这项工作吗?
最佳答案
这是因为 end()
返回一个类模板特化类型,它有一个类型为 test::test *
的参数.因此当operator-
应用于表达式 end() - 1
,参数相关查找在 test::test
的命名空间中也 .它会找到您的 operator-
并将迭代器和 int
传递给它.
您可以通过不接受任何类型作为参数来修复它。例如,尝试接受 (testExpr<A1, B1>, testExpr<A2, B2>)
反而。显示您所有的组合,可能有一种方法可以使用另一种方式来减少它们?
在我看来,以这种方式运行的实现应该是不符合规范的(尽管我认为这真的很恶心)。因为做 iterator - 1
被指定为前一个元素产生另一个迭代器,我认为不能做那样疯狂的事情。一种方法是将 operator 声明为非模板,直接接受迭代器类型和整数参数(迭代器的 difference_type
)。这样他们的版本应该总是首选。
关于c++ - std::vector 的表达式模板运算符重载问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3882414/