Проблема перегрузки оператора шаблона выражения с помощью 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), что приведет к множеству различных комбинаций.

Есть ли способ заставить это работать без указания всех комбинаций для каждого оператора?

2 ответа

Решение

Это потому что end() возвращает тип, который является специализацией шаблона класса, который имеет один аргумент типа test::test *, Таким образом, когда operator- применяется в выражении end() - 1поиск, зависящий от аргумента, также выглядит в пространстве имен test::test, Находит ваш operator- и передает его итератор и int,

Вы можете исправить это, не принимая ни один и все типы в качестве аргументов. Например, попробуйте принять (testExpr<A1, B1>, testExpr<A2, B2>) вместо. Покажите все свои комбинации, возможно, есть способ сократить их, используя другой способ их формулирования?

По моему мнению, реализация, которая действует таким образом, должна быть несоответствующей (я думаю, что это действительно отвратительно). Потому что делает iterator - 1 указывается, чтобы привести другой итератор к предыдущему элементу, и, я думаю, не должен делать что-то безумное. Одним из способов для этого является объявление оператора как не шаблонного, принимающего тип итератора и целочисленный аргумент (который является итератором difference_type) напрямую. Таким образом, их версия всегда должна быть предпочтительной.

Ваш код хорошо компилируется в VC++ версии 10 (из Visual Studio 2010 C++ Express), даже если он был изменен следующим образом:

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

    return 0;
}

Это может быть ограничением компиляторов. Шаблоны выражений являются своего рода стресс-тестом для поддержки шаблонов компилятором.

Другие вопросы по тегам