Я читал другие вопросы по этому поводу, но они либо не работают, либо я застрял.
Я пытаюсь динамически #import создать файл на основе флагов сборки, где имя моего импортированного файла имеет вид:
hardware_<hardware>_<version>.h
Я могу заставить это работать, но только без расширения файла .h, что не идеально.
Как мне изменить это, чтобы в конце стоял .h?
./hardware_XXX_YYY:
#define FOO "bar"
./main.cpp:
#include <iostream>
#define HARDWARE XXX
#define HARDWARE_VERSION YYY
#define CCC(x) #x
// This fails:
//#define BBB(ha, ver) CCC(hardware_##ha##_##ver##.h)
// This works:
#define BBB(ha, ver) CCC(hardware_##ha##_##ver)
#define AAA(ha, ver) BBB(ha, ver)
#include AAA(HARDWARE, HARDWARE_VERSION)
int main() {
std::cout << FOO << '\n';
}
Кстати, если вы опустите последний ## перед .h, он сгенерирует желаемый результат. #define BBB(ha, ver) CCC(hardware_##ha##_##ver.h)
@john Это поддерживается. См. en.cppreference.com/w/cpp/preprocessor/include пункт 3. Что не поддерживается, так это случаи, когда #include происходит из расширения макроса.
Препроцессор вроде бы формирует hardware_XXX_YYY. вместо hardware_XXX_YYY.h. Почему и почему первая форма не является допустимым токеном препроцессора?
Стандарт требует, чтобы вставка токена привела к созданию действительного токена. (описано, например, в Complete-concrete-concision.com/programming/c/… ) В общем, существует различие идентификаторов и знаков препинания. Таким образом, объединение последовательности символов (идентификатора?) с точкой (пунктуацией?) может оказаться недопустимым. На данный момент ответ на отбрасывание ## перед .h имеет какой-то смысл. (Должен признать слабую сторону всего этого рассуждения: я никогда не задумывался, как все это применимо к #include путям...)
@ 7478597 подразумевается, что если есть знак пунктуации, его левая и правая стороны должны быть действительным токеном? Это имело смысл, но я не мог уяснить это, прочитав стандарт. Вот почему удаление ## работает: hardware_##ha##_##ver дает действительный подтокен ", h также и они связаны пунктуатором? Это правильно?
Эмпирическое правило заключается в том, что если иначе он не сформирует другой действительный идентификатор, вам не нужен ##. ## в a##b необходим, потому что a и b в противном случае сформировали бы идентификатор ab (и, если возможно, расширились бы в макросе). ## в ver##.h не требуется, поскольку ver.h невозможно проанализировать как отдельный идентификатор.
Похоже на работу небольшого генератора кода, где вы создаете небольшой включаемый файл, содержащий для вас настоящий hardware_<hardware>_<version>.h. Этот заголовочный файл будет настолько маленьким, что вы, вероятно, сможете сгенерировать его из сценария, считывающего некоторую информацию о версии.





Вам не нужен дополнительный ## перед частью .h, поскольку .h не является частью анализа токена (ha и ver есть, и вам нужен дополнительный ## из-за подчеркивания).
Вот небольшой пример, включающий файл «string.h», созданный с помощью макросов. Опять же, st и .h не являются частью конкатенации, поэтому дополнительные ## не нужны.
#include <iostream>
#define CCC(x) #x
#define BBB(ha, ver) CCC(st##ha##ver.h)
#include BBB(ri,ng)
int main() {
std::cout << BBB(ri,ng)"\n";
}
Выход:string.h
Я уверен, что в какой-то момент id попробовала эту перестановку, но она не сработала. Должно быть, у него была какая-то другая проблема в попытке заставить что-то работать. Спасибо
st является частью конкатенации. Другой вопрос, заменяется ли идентификатор в расширении макроса.
C++ не поддерживает раскрытие макросов в директиве
#includeв стандартной комплектации. Поэтому, если вас интересует какое-то нестандартное решение, вам следует указать, какой компилятор вы используете.