2016-04-20 9 views
2

Я в замешательстве, почему следующий код компилируется в некоторых случаях, но не в других.Почему я могу вызвать эту стандартную библиотечную функцию C++ без std :: qualifier?

#include <iostream> 
#include <vector> 
#include <algorithm> 

int main(){ 
    std::vector<int> v(3); 
    int a[] = {3, 6, 2}; 
    std::copy(a, a+3, v.begin()); 
#define CASE 2 
#if CASE == 0 
    std::cout << *max_element(a, a+3) << "\n"; 
#elif CASE == 1 
    std::cout << *std::max_element(a, a+3) << "\n"; 
#else 
    std::cout << *max_element(v.begin(), v.end()) << "\n"; 
#endif 
    return 0; 
} 

Я поместил в трех случаях: СЛУЧАЙ 0 не удается собрать, потому что нет такого понятия, как «max_element». Я исправлю это в CASE 1, заменив вместо него «std :: max_element», и он делает компилируется и работает как ожидалось.

Однако, интересно для CASE 2 (технически ничего, кроме 0 или 1), он также компилируется и работает. Но CASE 2 имеет ту же проблему, что и CASE 0, так почему она работает?

+1

[Аргумент-зависимый поиск] (http://en.cppreference.com/w/cpp/language/adl). – songyuanyao

+1

@songyuanyao, поэтому этот код зависит от деталей реализации 'vector :: iterator'. Если бы это был тип non-class, тогда ADL завершил бы ошибку –

+0

, если я попытаюсь определить мою собственную версию max_element с тем же именем, а затем вызывая ее с использованием CASE 2 выше, компилятор жалуется, что «вызов max_element» неоднозначен, что Я предполагаю, что зависящий от аргументов поиск делает существующий конфликт max_element с тем, который я явно определил. Почему мне не разрешают это делать? Означает ли это, что зависящий от аргументов поиск загрязняет мое пространство имен, отличное от std? – xdavidliu

ответ

4

В последнем случае, который вы обозначаете «CASE 2», аргументы являются итераторами, которые для стандартной реализации библиотеки имеют определение типа в пространстве имен std.

Тогда аргумент-зависимый поиск, более известный как только ADL, и в настоящее время менее широко известное как Koenig поиск (после Andrew Koenig), находит имя функции в этом пространстве имен.


ADL - это механизм, который, например, находит нечлен operator+ для вас, когда вы пишете

std::string const a = "Blah"; 
foo(a + "Blah "); 

Но он может также найти обычные названные функции, а не только оператор.

К сожалению, аналогичного механизма для перехода в другую сторону не существует, гипотетический “ функциональный поиск ”, например, может найти тип, определенный в классе и используемый в выражении аргумента для вызова функции-члена этого класса.


С ¹ std::vector разрешаются использовать сырые указатели в качестве итераторов, вы не гарантируете, что код будет работать с другой стандартной реализацией библиотеки.

Примечание:
¹ std::vector и std::basic_string гарантии смежных внутренних буферов, и это позволяет сырые указатели как итераторы.

+0

« Поскольку std :: vector разрешено использовать исходные указатели в качестве итераторов », я не думаю, что для использования чего-либо, полученного из' std :: iterator'. – user657267

+0

@ user657267: Например, 'std :: list' не может использовать raw-указатели в качестве итераторов, потому что приращение такого итератора будет помещать вас в произвольную часть памяти (только мимо или в пределах выделенного узла). 'std :: vector' и' std :: basic_string' являются особенными в том, что они гарантируют непрерывные внутренние буферы. И это позволяет использовать исходные указатели как итераторы. –

+0

Я знаю, но до сих пор нет требования о том, чтобы типизированный тип 'std :: list :: iterator' определен внутри' std', если только я не понимаю требования. – user657267