Использование операторов из разных пространств имен в std::find

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

#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)
  • Как это можно исправить? (без изменения сгенерированного кода)

Редактировать:

Благодаря ответу Макса (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);
}

@LeonardoFaria Точно куда вы добавляете утверждение using?

Martin Bonner supports Monica 04.04.2019 15:43

Я добавлю фрагмент с using для лучшего понимания

Leonardo Faria 04.04.2019 15:46

@LeonardoFaria - Спасибо!

StoryTeller - Unslander Monica 04.04.2019 15:46

добавил фрагмент (он предпоследний)

Leonardo Faria 04.04.2019 15:49

Первый случай не работает из-за ADL — компилятор ищет в пространстве имен foo, а не foo::inner для operator==. Добавьте using inner::operator== в пространство имен foo.

Peter 04.04.2019 15:50
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
5
267
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

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

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

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

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

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

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

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

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

Но, безусловно, добавление оператора using добавит inner::operater== в глобальное пространство имен.

Martin Bonner supports Monica 04.04.2019 15:45

@MartinBonner В рамках того места, куда вы это поместили using. Именно поэтому работает второй случай. Но волшебным образом это не станет доступным для внутренностей std::find.

Max Langhof 04.04.2019 15:45

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