Страницы

Поиск по вопросам

четверг, 12 декабря 2019 г.

std::move вне пространства имен std

#cpp #cpp11


Почему этот код работает, если даже если мы не используем пространство имен std? 

#include 
#include 
#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
    


Ответы

Ответ 1



Это так называемый 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 void zoo(T & one, T & two) { std::swap(one, two); } 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 void zoo(T & one, T & two) { swap(one, two); } Теперь swap будет искаться в текущем пространстве имен и в пространстве имен своих аргументов. Но здесь возникает новая проблема. Что делать с типами, для которых нет swap? А для них мы будем использовать std::swap, просто добавим using в функцию: template void zoo(T & one, T & two) { using std::swap;//Обеспечит вызов std::swap для типов swap(one, two);//для которых не предоставлен более подходящий swap } Теперь, благодаря 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 void zoo(T & one, T & two) { using std::swap; swap(one, two); } 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

Ответ 2



Как я понимаю, работает ADL (Argument-Dependent Lookup), выполняющий поиск в соответствующем string пространстве имен. "По-моему, так" (с) Пух Если не так - пусть гуру подправят...

Комментариев нет:

Отправить комментарий