Проблема перегрузки оператора шаблона выражения с помощью std :: vector - PullRequest
2 голосов
/ 07 октября 2010

В настоящее время я работаю над числовой библиотекой, которая использует шаблоны выражений. К сожалению, я столкнулся с проблемой перегрузки моего оператора. Рассмотрим следующий урезанный пример.

#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 ]

2 голосов
/ 08 октября 2010

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

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

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

0 голосов
/ 07 октября 2010

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

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

    return 0;
}

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

...