Стандарты программирования на С++. 101 правило и рекомендация | страница 101
Следуя данному совету, вы сможете избежать трудно обнаруживаемых ошибок в вашем коде и необходимости разбираться с очень тонкими моментами языка, с которыми вы просто не должны сталкиваться.
Вот реальный пример, который был опубликован в группе новостей:
>#include
>namespace N {
>struct X { };
>template
>int* operator+(T , unsigned) {/* некоторые действия */}
>}
>int main() {
> std::vector
> v[0];
>}
Инструкция >v[0];
компилируется в некоторых реализациях стандартной библиотеки, но не во всех. Попробуем кратко пересказать эту длинную историю. Очень тонкая проблема связана с тем, что внутри большинства реализаций >vector
спрятан код наподобие >v.begin()+n
, и поиск имен для функции >operator+
может достичь пространства имен (в нашем случае >N
) типа, для которого инстанцирован вектор (в нашем случае >X
). Достигнет ли поиск этого пространства имен или нет — зависит от того, как определен >vector
в данной версии реализации стандартной библиотеки. Однако если поиск достигает >N
, то здесь он находит >N::operator+
. Наконец, в зависимости от используемых типов, компилятор может просто посчитать, что для >vector
оператор >N::operator+
имеет лучшее соответствие, чем оператор >std::operator+
из реализации стандартной библиотеки (который и должен был быть вызван). (Один из способов избежать такой неприятности в реализации стандартной библиотеки — не использовать код >v.begin()+n
таким образом, что он вносит непреднамеренную точку настройки: либо надо изменить код так, чтобы тип >v.begin()
никаким образом не зависел от параметра шаблона, либо вызов >operator+
следует переписать с указанием полного квалифицированного имени. См. рекомендацию 65.)
Коротко говоря, вряд ли вам удастся выявить истинную причину выводимого сообщения об ошибке. Если вам, конечно, повезет и вы получите это сообщение об ошибке, так как в случае невезения выбранный оператор >N::operator+
окажется, к несчастью, вполне подходящим с точки зрения компилятора, и программа скомпилируется успешно, но вот результаты ее работы могут оказаться совершенно неожиданными...
Вы думаете, что вам не приходилось с этим сталкиваться? Попробуйте вспомнить, бывало ли такое в вашей практике, что ваш код, например, с использованием стандартной библиотеки приводил к удивительным и непонятным ошибкам компиляции? А после того как вы слегка меняли ваш код, порой просто меняя местами отдельные куски кода, все вдруг начинало работать и у вас оставалось только небольшое недоумение по поводу глупого компилятора, который запутался в трех строках? Практически все мы попадали в подобные ситуации, когда причиной неприятностей становилась рассматриваемая проблема, т.е. когда ADL находил имена из неподходящего пространства имен просто потому, что типы из этих пространств имен использовались поблизости друг от друга.