Ситуация такова, что некоторые функции-члены 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
Пространство имен.
Как вы сами узнали, добавив функцию-член 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()
, Я бы не использовал трюки с признаками типа, чтобы получить то же поведение, что и косвенный подход, и делает интерфейсы классов более сложными для понимания (помните девиз Страуструпа: «представлять свои идеи непосредственно в коде»).
Вы можете использовать этот трюк
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