Просто в качестве примера. У нас есть класс шаблона потока, который использует класс реализации thread_impl. thread_impl реализован как для windows, так и для unix, поэтому есть заголовочные файлы thread_impl_win и thread_impl_nix. Заголовочный файл потока должен включать один из них, чтобы можно было использовать класс thread_impl.

аюсь сгенерировать имя включаемого файла в макросе. Это должно быть законно в C ++:

#define INCLUDE_FILE "module_impl_win.hpp"
#include INCLUDE_FILE

это работает нормально, но как только я пытаюсь сгенерировать имя файла, он не может скомпилировать

#define INCLUDE_FILE(M) M##"_impl_win.hpp"
#include INCLUDE_FILE("module")

На самом деле это дает мне предупреждение на MSVC2010

предупреждение C4067: неожиданные токены после директивы препроцессора - ожидается newlin

но это не включает файл.

В чем проблема? Как я могу избавиться от этого?

Ответы на вопрос(3)

Вы также можете использовать Boost Preprocessor, особенноBOOST_PP_STRINGIZE/BOOST_PP_CAT макросы:

#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/stringize.hpp>

#define INCLUDE_FILE(M) BOOST_PP_STRINGIZE(BOOST_PP_CAT(M, _impl_win.hpp))

// expands to: #include "module_impl_win.hpp"
#include INCLUDE_FILE(module)

(СрC Macro - Динамический #include)

Обратите внимание, что это страдает от той же проблемы, что и ответ @ Эндрю (начальное подчеркивание = зарезервированный идентификатор).

#include "module""_impl_win.hpp"

Это генерирует те же предупреждения и ошибки, которые вы видите, но в несколько более очевидной форме.

Хотя компилятор примет этот синтаксис, препроцессор не примет.

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

 ledokol20 янв. 2011 г., 07:29
Спасибо, не знал, что это объединяет такие строки. Представьте, что есть сотни файлов, которые содержат заголовки для конкретной платформы с #ifdef ... #endif. Если завтра я добавлю поддержку еще одной платформы, мне нужно будет отредактировать все эти файлы вместо того, чтобы просто редактировать один макрос и добавлять файлы реализации для конкретной платформы. Печально.
 ledokol20 янв. 2011 г., 07:49
Вы имеете в виду, почему PIMPL не используется для разделения кода, специфичного для платформы? Ну, это не может использоваться везде. Существует множество шаблонных классов, которые требуют объявления класса реализации для конкретной платформы. Поэтому я должен разделить его на файлы заголовков и реализации.
 ledokol20 янв. 2011 г., 07:54
Просто в качестве примера. У нас есть класс шаблона потока, который использует класс реализации thread_impl. thread_impl реализован как для windows, так и для unix, поэтому есть заголовочные файлы thread_impl_win и thread_impl_nix. Заголовочный файл потока должен включать один из них, чтобы можно было использовать класс thread_impl.
 James McNellis20 янв. 2011 г., 07:43
@ledokol: Почему функциональные возможности платформы не могут быть разделены на отдельные заголовки и исходные файлы, которые не включены нигде? Должно быть легко объединить зависящую от платформы и зависящую от платформы функциональность в относительно небольшой набор файлов.
Решение Вопроса

используя макрос цитирования помощника. Нечто подобное даст вам то, что вы хотите:

#define QUOTEME(M)       #M
#define INCLUDE_FILE(M)  QUOTEME(M##_impl_win.hpp)

#include INCLUDE_FILE(module)
 ledokol20 янв. 2011 г., 07:37
Кстати, насколько это портативный?
 James McNellis20 янв. 2011 г., 07:37
Вы должны быть осторожны с этим подходом._impl_win является идентификатором-токеном, и, поскольку он начинается с подчеркивания (и находится в пространстве имен макроса), он зарезервирован для реализации. Вы должны прервать ведущий_ и объединить это отдельно, хотя из головы, я не уверен, как это сделать здесь, так как_ Сам по себе является зарезервированным идентификатором.
 ledokol20 янв. 2011 г., 07:45
@ Джеймс МакНеллис: только что проверил стандарт. Да, прости. Вы были правы (каждое имя, начинающееся с подчеркивания, зарезервировано для реализации для использования в качестве имени в глобальном пространстве имен). Может быть, тогда лучше включить «module_» и объединить его с impl_win.hpp?
 James McNellis20 янв. 2011 г., 07:40
@ledokol:Любые имя, начинающееся с подчеркивания, зарезервированов глобальном пространстве имен (и пространство имен макросов, которое является «глобальным» своего рода пространством имен). Что касается переносимости, в целом этот подход должен быть переносимым, хотя есть некоторые особенности в том, как указывается расширение макросов в директивах include.
 ledokol20 янв. 2011 г., 07:38
@James McNellis: Стандартный резервирует только имена с подчеркиванием, за которым следует символ верхнего регистра (или имена, содержащие двойное подчеркивание). Я не знаю, почему Саттер рекомендует избегать использования подчеркивания везде ...

Ваш ответ на вопрос