пятница, 27 марта 2009 г.

Ошибка в стандартном инклюде

Интересную ошибку словил на днях...
$ c++ ... -c file.cpp -o file.o
In file included from /usr/include/c++/4.2/bits/basic_ios.h:44,
from /usr/include/c++/4.2/ios:50,
from /usr/include/c++/4.2/ostream:45,
from /usr/include/c++/4.2/iostream:45,
from configuration.h:4,
from wrap.h:15,
from file.cpp:15:
/usr/include/c++/4.2/bits/locale_facets.h:4576: error: template-id 'do_get<>' for 'std::string std::messages::do_get(int, int, int, const std::string&) const' does not match any template declaration
$

Всякие совпадения с реальными файлами являются случайными :)

Причем выяснилось, что если поменять инклюды местами - становится легче. В этом надо разобраться...

Проблема возникает с темплейтами в locale_facets.h.

Для начала прогоню две версии через препроцессор. После долгого сравнения выясняется, что в правильной версии проблемная строка (locale_facets.h:)выглядит так:
 template<>
wstring
messages::do_get(catalog, int, int, const wstring&) const;

А в неправильной:
  template<>
string
messages::do_get(catalog, int, int, const string&) const;

Очень странно, с какого праздника препроцессор в исходном тексте:
  template<>
wstring
messages::do_get(catalog, int, int, const wstring&) const;

заменил wstring на string?

Да очень просто. В одном из инклюдов проекта кто-то очень умный поставил:
#define wstring string

Если все стандартное инклюдится заранее - проблем нету. В противном случае стандартные инклюды тянутся из проектных инклюдов, и в результате ошибка компиляции. И как это называется?

Вообще я раньше наивно полагал что не стоит выносить сор из избы, то бишь каждый инклюд должен сам инклюдить все, что нужно ему для успешной компиляции.

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

Вот, как говориться КСCЗБ. Ну и кто написал эту ерунду (это я про define), пойду искать...