Почему этот код работает, если даже если мы не используем пространство имен std?
#include
int main() {
std::string s = "test";
std::cout << move(s); // <= move без std::, никакого using namespace std нет
}
Однако move(1) не скомпилируется, тк нет функции move, а std::move(1) - да.
Проверено в g++6.3 -std=c++14, clang++5.0 и 6.0 -stdc++1z
Ответ
Это так называемый Argument-Dependent Lookup (ADL).
Если кратко, то к функциям-кандидатам при поиске подходящей функции также добавляются функции из пространств имен фактических аргументов.
Рассмотрим простой пример (в конце имеется полный код):
namespace First
{
struct Type {};
void foo(Type)
{
std::cout << "First foo" << std::endl;
}
void bar(First::Type, First::Type)
{
std::cout << "First::bar" << std::endl;
}
}
namespace Second
{
struct Type {};
void foo(Type)
{
std::cout << "Second foo" << std::endl;
}
void bar(First::Type, Second::Type)
{
std::cout << "Second::bar" << std::endl;
}
}
int main()
{
First::Type f;
Second::Type s;
//Аргумент из пространства имен First,
//поэтому поиск будем производить и в пространстве имен First
foo(f);
//Аргумент из пространства имен Second,
//поэтому поиск будем производить и в пространстве имен Second
foo(s);
//Один аргумент из пространства имен First, другой - из Second.
//Поэтому поиск будет производиться и в First и в Second.
//Но для вызова подходит только функция Second::bar
bar(f, s);
}
Рассмотрим более практический случай, когда ADL помогает делу. Возьмем простой шаблон функции, которая во время работы где-то в своих недрах обменивает значения двух своих аргументов:
template
zoo использует std::swap для обмена значений.
Представим, что два объекта типа First::Type можно обменять местами эффективнее, чем это делает std::swap. Нам необходимо, чтобы для типа First::Type эта функция использовала более эффективный обмен.
Для начала необходимо добавить функцию swap в пространство имен First
namespace First
{
//...
void swap(Type &, Type &)
{
std::cout << "First::swap" << std::endl;
}
}
Теперь необходимо как-то заставить zoo вызывать Second::swap вместо std::swap. В этом нам поможет ADL, мы просто убираем пространства имен при использовании swap
template
Теперь swap будет искаться в текущем пространстве имен и в пространстве имен своих аргументов. Но здесь возникает новая проблема. Что делать с типами, для которых нет swap? А для них мы будем использовать std::swap, просто добавим using в функцию:
template
Теперь, благодаря ADL для типов для которых предусмотрен собственный swap будет использоваться именно он, а для других - стандартный.
//...
zoo(f, f);
int a = 10;
int b = 20;
zoo(a, b);
std::cout << a << " " << b << std::endl;
Полный код примера:
#include
namespace First
{
struct Type {};
void foo(Type)
{
std::cout << "First foo" << std::endl;
}
void bar(First::Type, First::Type)
{
std::cout << "First::bar" << std::endl;
}
void swap(Type &, Type &)
{
std::cout << "First::swap" << std::endl;
}
}
namespace Second
{
struct Type
{};
void foo(Type)
{
std::cout << "Second foo" << std::endl;
}
void bar(First::Type, Second::Type)
{
std::cout << "Second::bar" << std::endl;
}
void swap(Type &, Type &)
{
std::cout << "Second::swap" << std::endl;
}
}
template
int main()
{
First::Type f;
Second::Type s;
foo(f);
foo(s);
bar(f, s);
zoo(f, f);
zoo(s, s);
int a = 10;
int b = 20;
zoo(a, b);
std::cout << a << " " << b << std::endl;
}
http://rextester.com/LWCQY38186
Комментариев нет:
Отправить комментарий