Стандарты программирования на С++. 101 правило и рекомендация | страница 101



Обсуждение

Следуя данному совету, вы сможете избежать трудно обнаруживаемых ошибок в вашем коде и необходимости разбираться с очень тонкими моментами языка, с которыми вы просто не должны сталкиваться.

Вот реальный пример, который был опубликован в группе новостей:

>#include


>namespace N {

>struct X { };

>template

>int* operator+(T , unsigned) {/* некоторые действия */}

>}


>int main() {

> std::vector v(5);

> v[0];

>}

Инструкция >v[0]; компилируется в некоторых реализациях стандартной библиотеки, но не во всех. Попробуем кратко пересказать эту длинную историю. Очень тонкая проблема связана с тем, что внутри большинства реализаций >vector::operator[] спрятан код наподобие >v.begin()+n, и поиск имен для функции >operator+ может достичь пространства имен (в нашем случае >N) типа, для которого инстанцирован вектор (в нашем случае >X). Достигнет ли поиск этого пространства имен или нет — зависит от того, как определен >vector::iterator в данной версии реализации стандартной библиотеки. Однако если поиск достигает >N, то здесь он находит >N::operator+. Наконец, в зависимости от используемых типов, компилятор может просто посчитать, что для >vector::iterator оператор >N::operator+ имеет лучшее соответствие, чем оператор >std::operator+ из реализации стандартной библиотеки (который и должен был быть вызван). (Один из способов избежать такой неприятности в реализации стандартной библиотеки — не использовать код >v.begin()+n таким образом, что он вносит непреднамеренную точку настройки: либо надо изменить код так, чтобы тип >v.begin() никаким образом не зависел от параметра шаблона, либо вызов >operator+ следует переписать с указанием полного квалифицированного имени. См. рекомендацию 65.)

Коротко говоря, вряд ли вам удастся выявить истинную причину выводимого сообщения об ошибке. Если вам, конечно, повезет и вы получите это сообщение об ошибке, так как в случае невезения выбранный оператор >N::operator+ окажется, к несчастью, вполне подходящим с точки зрения компилятора, и программа скомпилируется успешно, но вот результаты ее работы могут оказаться совершенно неожиданными...

Вы думаете, что вам не приходилось с этим сталкиваться? Попробуйте вспомнить, бывало ли такое в вашей практике, что ваш код, например, с использованием стандартной библиотеки приводил к удивительным и непонятным ошибкам компиляции? А после того как вы слегка меняли ваш код, порой просто меняя местами отдельные куски кода, все вдруг начинало работать и у вас оставалось только небольшое недоумение по поводу глупого компилятора, который запутался в трех строках? Практически все мы попадали в подобные ситуации, когда причиной неприятностей становилась рассматриваемая проблема, т.е. когда ADL находил имена из неподходящего пространства имен просто потому, что типы из этих пространств имен использовались поблизости друг от друга.