std::vector 的表达式模板运算符重载问题

发布于 2024-09-26 04:12:40 字数 1263 浏览 1 评论 0原文

我目前正在开发一个使用表达式模板的数字库。不幸的是,我遇到了运算符重载的问题。考虑以下精简示例。

#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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

说好的呢 2024-10-03 04:12:40

这是因为 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 type test::test *. Thus when operator- is applied in the expression end() - 1, argument dependent lookup looks also in the namespace of test::test. It finds your operator- and passes it the iterator and an int.

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's difference_type) directly. This way their version should always be preferred.

最美的太阳 2024-10-03 04:12:40

您的代码在 VC++ 版本 10(来自 Visual Studio 2010 C++ Express)中编译正常,即使进行如下修改:

int main()
{ 
    vector<test::test> vec;
    test::test instance = stuff(vec);

    return 0;
}

这可能是编译器的限制。表达式模板在某种程度上是对编译器模板支持的压力测试。

Your code compiles OK in VC++ version 10 (from Visual Studio 2010 C++ Express), even when modified like this:

int main()
{ 
    vector<test::test> vec;
    test::test instance = stuff(vec);

    return 0;
}

This could be a limitation of the compilers. Expression templates are somewhat of a stress test for a compiler's template support.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文