Day 19.
Возвращаясь к
__FILE__ и __LINE__. Вы можете изменить их значения с помощью
#line:
#line 123 "name.cpp"
int main()
{
std::cout << __FILE__ << ' ' << __LINE__ << std::endl;
std::cout << __FILE__ << ' ' << __LINE__ << std::endl;
std::cout << __FILE__ << ' ' << __LINE__ << std::endl;
}
Результат будет:
name.cpp 126
name.cpp 127
name.cpp 129
Или можно только строку переопределить:
#line 123
Круто. Но зачем?
Представьте, что вы генерируете код. И ваш сгенерированный файл имеет название generated_228228.cpp. Если вы начнёте выдавать юзеру ошибки, основанный на
__FILE__/__LINE__ в этом файле, юзер будет в замешательстве. Он-то ни про какой generated_228228.cpp не в курсе. Потому в начале файла вы можете воткнуть:
#line 1 "query.sql"
Что возволяет вам ссылаться на оригинальный источник.
#line кстати влияет не только на макросы, но и на
std::source_location. Насколько я понимаю (что может быть неправдой), компилятор сам активно пользуется подобным приёмом. Вы же когда подключаете инсклуд, вы фактически получаете один огромный cpp файл. Но в нём при этом все вызове
__FILE__, __LINE__ и других связанных штук работают как будто находятся в разных файлах. Давайте возьмём Hello world:
#include <iostream>
int main() {
std::cout << "Hello, thisnotes!";
}
и скомпилируем
clang -E main.cpp. Мы получим какое-то полотно (от iostream), а в конце будет:
// полотно
# 2 "main.cpp" 2
int main() {
std::cout << "Hello, thisnotes!";
}
Вот это
# 2 "main.cpp" 2 — расширенная версия #line у компилятора. То есть он кроме вставки инклудом файла ещё и добавляет в нужное место #line-like команду, подправляющую текущие значения строк и имён файлов. Хотя файл у вас в итоге всего один. Скажу ли я что-то про
__FUNCTION__, __PRETTY_FUNCTION__ и __func__? Нет. Ведь это не часть препроцессора, а скорее «implicit» переменные. Так что на самостоятельное изучение.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.