ADL в случае одноименной функции-члена

Ситуация такова, что некоторые функции-члены bar::Bar::frobnicate хочет использовать ADL, чтобы найти функцию из некоторого неизвестного пространства имен внутри функции с одинаковым именем. Однако он находит только свое имя.

Прецедент

(Заметка что на самом деле, Bar это Foo-агностический шаблон; это просто воспроизводимый, минимальный тестовый сценарий)

namespace foo {
struct Foo {};
void frobnicate(Foo const &) {}
}

namespace bar {
struct Bar {
void frobnicate() {
foo::Foo foo;
frobnicate(foo); // <-- error
}
};
}

int main () {
bar::Bar x;
x.frobnicate();
frobnicate(foo::Foo());
}

Результаты в:

test.cc: In member function ‘void bar::Bar::frobnicate()’:
test.cc:10:31: error: no matching function for call to ‘bar::Bar::frobnicate(foo::Foo&)’
test.cc:10:31: note: candidate is:
test.cc:8:18: note: void bar::Bar::frobnicate()
test.cc:8:18: note:   candidate expects 0 arguments, 1 provided

стандарт

Я понимаю, что это правильное поведение компилятора:

3.4.1 Поиск безоговорочного имени [Basic.lookup.unqual]

(…) поиск имени заканчивается, как только найдено объявление для имени (…)

и только после неудачный поиск, в игру вступает зависимый поиск:

3.4.2 Аргумент-зависимый поиск имени [Basic.lookup.argdep]

Когда выражение postfix в вызове функции (5.2.2) является безусловным идентификатором, другие пространства имен не учитываются
во время обычного неквалифицированного поиска (3.4.1) можно искать

Временное решение

Мой текущий обходной путь — ввести специальный класс черт, который не определяет само конфликтующее имя:

    struct BarTraits {
void frobnicate_(foo::Foo const &b) {
frobnicate(b);
}
};

или эта более легкая версия:

    void frobnicate_(foo::Foo const &c) { frobnicate(c); }

Вопрос

Есть ли лучшие альтернативы, чем введение таких классов черт?

Явно квалифицируя вызов как foo::frobnicate(foo) здесь не вариант, потому что (как уже упоминалось) Bar класс является шаблоном Foo в действительности, и должен работать не только для типов в foo Пространство имен.

5

Решение

Как вы сами узнали, добавив функцию-член frobnicate к интерфейсу класса Bar (или же Bar<T> в случае шаблона), не позволит ADL найти foo::frobnicate,

Самый легкий —и в этом случае идиоматический— способ добавить frobnicate функциональность к классу Bar (или к шаблону класса Bar<T>) добавить функцию, не являющуюся членом frobnicate(Bar) (или шаблон функции frobnicate(Bar<T>)) в пространство имен bar

namespace foo {
struct Foo {};
void frobnicate(Foo const &)  {}
}

namespace bar {
template<class T>
struct Bar {
T t;
};

template<class T>
void frobnicate(Bar<T> const& b)
{
frobnicate(b.t);
}
}

int main () {
bar::Bar<foo::Foo> x;
frobnicate(x);
frobnicate(foo::Foo());
}

Если вы настаиваете на наличии функции-члена, вам придется переименовать ее в нечто вроде do_frobnicate(), Я бы не использовал трюки с признаками типа, чтобы получить то же поведение, что и косвенный подход, и делает интерфейсы классов более сложными для понимания (помните девиз Страуструпа: «представлять свои идеи непосредственно в коде»).

2

Другие решения

Вы можете использовать этот трюк

namespace dummy { void your_func(may be some parameteres); }
struct bar {
void member() {
using dummy::your_func; // now your call will find that and ADL will kick in
0

По вопросам рекламы [email protected]