【问题标题】:Expression template operator overloading problem with std::vectorstd::vector 的表达式模板运算符重载问题
【发布时间】:2011-04-22 09:31:59
【问题描述】:

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

#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),这会导致很多不同的组合。

有没有办法在不为每个运算符拼出所有组合的情况下完成这项工作?

【问题讨论】:

  • 您的精确示例是否无法编译?我能够在 g++ 4.4.1 上很好地编译它。
  • 错误信息来自 clang。 g++ 在那里也失败了,但错误消息更糟。我还尝试了 gcc 版本 4.3.4 (Ubuntu 4.3.4-10ubuntu1) 和 gcc 版本 4.1.3 20080704 (prerelease) (Ubuntu 4.1.2-27ubuntu1)。两者都失败了。
  • 使用 gcc 3.4.6 失败,使用 gcc 4.4.1 编译,使用 gcc 4.4.4、gcc 4.5.2、gcc 4.6-alpha 失败。错误是一样的(在vector::iterator和一个int之间的operator-的结果上没有operator*)

标签: c++ templates stl operator-overloading expression-templates


【解决方案1】:

这是因为end() 返回的类型是类模板特化,它有一个test::test * 类型的参数。因此,当operator- 应用于表达式end() - 1 时,依赖于参数的查找test::test 的命名空间中查找。它找到您的operator- 并将其传递给迭代器和int

您可以通过不接受任何和所有类型作为参数来修复它。例如,尝试改为接受(testExpr&lt;A1, B1&gt;, testExpr&lt;A2, B2&gt;)。展示你所有的组合,可能有一种方法可以用另一种方式来减少它们?

在我看来,以这种方式运行的实现应该是不合格的(虽然我认为这真的很恶心)。因为执行iterator - 1 被指定为前一个元素产生另一个迭代器,并且不能做那样疯狂的事情,我想。一种方法是将 operator 声明为直接接受迭代器类型和整数参数(它是迭代器的 difference_type)的非模板。这样他们的版本应该总是首选。

【讨论】:

  • 虽然我仍然不确定这是标准中的错误还是不准确,但我决定通过使用脚本生成必要的组合来发布。
【解决方案2】:

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

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

    return 0;
}

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

【讨论】:

    猜你喜欢
    • 2018-12-16
    • 2011-06-11
    • 1970-01-01
    • 1970-01-01
    • 2015-01-18
    • 1970-01-01
    • 2021-02-13
    • 2014-11-04
    • 1970-01-01
    相关资源
    最近更新 更多