Использование операторов из разных пространств имен в std :: find - PullRequest
4 голосов
/ 04 апреля 2019

У меня есть следующий код, который генерируется автоматически:

#include <vector>
#include <algorithm>

namespace foo{  
    struct S{};
    namespace inner{
        bool operator==(const S&,const S&){return true;}
    }
}

namespace bar{
    void func();
}

Теперь я хочу найти контейнер для S объекта, используя алгоритм find STL:

void bar::func(){
    std::vector<foo::S> v;
    foo::S s;
    std::find(v.begin(),v.end(),s);
}

Однако я получаю эту ошибку:

/opt/compiler-explorer/gcc-8.3.0/include/c++/8.3.0/bits/predefined_ops.h:241:17:
error: no match for 'operator==' (operand types are 'foo::S' and 'const foo::S')

  { return *__it == _M_value; }

Даже после добавления using foo::inner::operator==; я получаю ту же ошибку:

void bar::func(){
    using foo::inner::operator==;
    std::vector<foo::S> v;
    foo::S s;
    std::find(v.begin(),v.end(),s);
}

Однако, когда я делаю это, это работает:

void bar::func(){
    std::vector<foo::S> v;
    foo::S s;
    std::find_if(v.begin(),v.end(),[s](foo::S e){
        using foo::inner::operator==;
        return s==e;
    });
}

Мои два вопроса:

  • Почему в первом примере выдается ошибка? (после добавления using)
  • Как это можно исправить? (без изменения сгенерированного кода)

Edit:

Благодаря ответу Макса (https://stackoverflow.com/a/55517500/8900666) я нашел способ исправить эту проблему (немного некрасиво, но работает):

// Generated code
#include <vector>
#include <algorithm>

namespace foo{  
    struct S{};
    namespace inner{
        bool operator==(const S&,const S&){return true;}
    }
}
namespace bar{
    void func();
} 

// My code
namespace foo{
    using inner::operator==;
}

void bar::func(){
    std::vector<foo::S> v;
    foo::S s;
    std::find(v.begin(),v.end(),s);
}

1 Ответ

4 голосов
/ 04 апреля 2019

Проблема в зависимом от аргументов поиске (ADL).

Где-то в шаблоне std::find есть if (*it == value), где value и it являются зависимыми типами.Это означает, что компилятор будет ждать, пока не будет создан экземпляр шаблона, чтобы найти правильный operator== для использования.

Но места, которые он ищет для operator==, более или менее ограничены (не вдаваясь слишком глубоко)в детали поиска безусловного имени):

  • Все включающие пространства имен - но поиск здесь останавливается при поиске any operator==.(Не относится к вам, но может сбить с толку людей, которые просто добавляют операторы, например, для std объектов в глобальное пространство имен, например, "support" operator+ для std::vector).

  • ADL выполняется - пространства имен объектов (откуда *it и *value взяты) ищутся на соответствие operator==.

Но operator==, который выхочу использовать нельзя найти таким образом - он находится в другом (более глубоком) пространстве имен.По сути, это ошибка в сгенерированном коде - операторы всегда должны находиться в том же пространстве имен, в котором определены объекты, с которыми они работают.

Итак, ответы таковы:

  1. Ваш operator== не найден, потому что он находится в неправильном пространстве имен.

  2. Здесь нет проблем, потому что в лямбде правильный операторнайдено, и std::find_if просто напрямую использует лямбду (без поиска).

...