std::vector 的表达式模板运算符重载问题
我目前正在开发一个使用表达式模板的数字库。不幸的是,我遇到了运算符重载的问题。考虑以下精简示例。
#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.
由于某种原因,编译器会查找测试命名空间并找到我的通用运算符。我将这种形式与一些特征魔法一起使用,以减少我必须为操作员制作的版本数量。它应该接受 4 种不同的数据类型(包括 double 和 int),这会导致很多不同的组合。
有没有办法让这项工作无需拼写出每个运算符的所有组合?
I'm currently working on a numerical library that uses expression templates. Unfortunately I encountered a problem with my operator overloads. Consider the following stripped down example.
#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()
{ }
Which gives the following error message when compiling with gcc 4.4.3 or 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.
For some reason the compilers do a lookup into the test namespace and find my general operator. I used this form together with some traits magic to reduce the number of version i had to make for the operator. It should accept 4 different datatypes (including double and int) which would lead to a lot of different combinations.
Is there any way to make this work without spelling out all combinations for every operator?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是因为
end()
返回一种类模板特化类型,该类型具有一个test::test *
类型的参数。因此,当在表达式end() - 1
中应用operator-
时,参数相关查找也会在test 的命名空间中查找: :测试
。它找到您的operator-
并向其传递迭代器和int
。您可以通过不接受任何和所有类型作为参数来修复它。例如,尝试接受
(testExpr, testExpr)
。显示你所有的组合,是否有办法用另一种方式来制定它们来减少它们?在我看来,以这种方式执行的实现应该是不合格的(尽管我认为这真的很恶心)。因为指定执行
iterator - 1
是为了生成前一个元素的另一个迭代器,所以我认为不能做这样疯狂的事情。一种方法是将运算符声明为直接接受迭代器类型和整数参数(属于迭代器的difference_type
)的非模板。这样他们的版本应该始终是首选。This is because
end()
returns a type that is a class template specialization which has one argument of typetest::test *
. Thus whenoperator-
is applied in the expressionend() - 1
, argument dependent lookup looks also in the namespace oftest::test
. It finds youroperator-
and passes it the iterator and anint
.You could fix it by not accepting any and all types as arguments. For example, try accepting
(testExpr<A1, B1>, testExpr<A2, B2>)
instead. Show all your combinations, possibly there is a way to cut them down using another way to formulate them?In my opinion, an implementation that acts that way should be non-conforming (I think this is really disgusting though). Because doing
iterator - 1
is specified to yield another iterator to the previous element and must not do something crazy like that, I think. One way for it is to declare operator as a non-template accepting the iterator type and the integer argument (which is of the iterator'sdifference_type
) directly. This way their version should always be preferred.您的代码在 VC++ 版本 10(来自 Visual Studio 2010 C++ Express)中编译正常,即使进行如下修改:
这可能是编译器的限制。表达式模板在某种程度上是对编译器模板支持的压力测试。
Your code compiles OK in VC++ version 10 (from Visual Studio 2010 C++ Express), even when modified like this:
This could be a limitation of the compilers. Expression templates are somewhat of a stress test for a compiler's template support.