Каково худшее реальное злоупотребление macros/pre-processor, с которым Вы когда-либо сталкивались?

Поскольку я не знаю, какова цель вашего заявления, не могу сказать много.

Но если вы хотите сделать SSR с React , я рекомендую вам взглянуть на эту структуру https://github.com/zeit/next.js [110 ], используйте его в качестве внешнего интерфейса и паруса в качестве API.

nextjs имеет богатые документы и множество примеров, вы можете использовать его, не касаясь сервера, или с вашим собственным сервером, таким как Express, Hapi, Koa.

176
задан 9 revs, 5 users 42% 23 May 2017 в 12:34
поделиться

65 ответов

Другая часть 'творческого' использования препроцессора, хотя это находится больше в терминологии, используемой, чем в механике (которые являются невероятно приземленными):

/***********************************************************************
 * OS2 and PCDOS share a lot of common codes.  However, sometimes
 * OS2 needs codes similar to those of UNIX.  NOTPCDOS is used in these
 * situations
 */

#ifdef OS2
#define PCDOS
#define NOTPCDOS
#else /* OS2 */
#ifndef PCDOS
#define NOTPCDOS
#endif /* PCDOS */
#endif /* OS2 */

Подлинный код - я думал, что удалил его, но по-видимому нет. Я, должно быть, сделал так в некотором временном ответвлении и не получил разрешение перепроверить его в основной код. Еще один объект для, 'чтобы сделать' список.

1
ответ дан 2 revs 23 November 2019 в 20:20
поделиться

Хорошие макросы: (хотя лично мне не нравятся двойные круглые скобки, требуемые использовать этот синтаксис; я предпочитаю любого vararg макросы (только C99) или что-то как PRINTF_0, PRINTF_1, и т.д., в зависимости от количества аргументов)

#ifdef DEBUG
#define PRINTF(x) printf x
#else
#define PRINTF(x)
#endif

Уменьшает размер кода / время выполнения (первые больше, чем второе) для неотладочной сборки; также предотвращает просачивающиеся текстовые строки отладки, которые могут изложить небольшую угрозу безопасности

2
ответ дан 2 revs, 2 users 91% 23 November 2019 в 20:20
поделиться

Связанный с напыщенной речью Raymond следующее ужасное (по-моему, конечно) макрос:

#define CALL_AND_CHECK(func, arg) \
    int result = func(arg);       \
    if(0 != result)               \
    {                             \
        sys.exit(-1);             \
    }                             \

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

Как в стороне, если только станд.:: tr1:: функция была вокруг, когда этот макрос был записан, у меня будет неделя моей жизни назад!

2
ответ дан Aaron 23 November 2019 в 20:20
поделиться

Когда я сначала столкнулся с макросами в C, им озадачивали меня в течение многих дней. Ниже то, с чем я сталкивался. Я предполагаю, что это имеет смысл экспертам C и супер эффективно однако, чтобы я попытался разработать то, что точно шло на предназначенное вырезание и вставление всех других макросов вместе, пока целая функция не могла быть просмотрена. Конечно, это не хорошая практика?! Что случилось с использованием простой функции?!

#define AST_LIST_MOVE_CURRENT(newhead, field) do { \
typeof ((newhead)->first) __list_cur = __new_prev; \
AST_LIST_REMOVE_CURRENT(field); \
AST_LIST_INSERT_TAIL((newhead), __list_cur, field); \
} while (0) 
2
ответ дан sipwiz 23 November 2019 в 20:20
поделиться

Попытайтесь отладить большой проект, который действительно любит макросы, и существует много макросов, которые называют другие макросы, которые называют другие макросы и т.д. и т.д. (5-10 уровней макросов не был то, что редкий)

И затем добавили его большого количества #ifdef этот macrot #else, что макрос, поэтому если Вы следуете за кодом это как дерево различных путей, это может пойти.

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

1
ответ дан Johan 23 November 2019 в 20:20
поделиться

Худшие злоупотребления (и я виновен в выполнении этого иногда), использует препроцессор в качестве своего рода замены файла данных, т.е.:

#define FOO_RELATION \  
BAR_TUPLE( A, B, C) \  
BAR_TUPLE( X, Y, Z) \ 

и затем где-то в другом месте:

#define BAR_TUPLE( p1, p2, p3) if( p1 ) p2 = p3;
FOO_RELATION
#undef BAR_TUPLE

, который приведет к:

if( A ) B = C;
if( X ) Y = Z;

Этот шаблон может использоваться, чтобы сделать, все виды (ужасного) материала... еще генерируют операторы переключения или огромный если блоки или интерфейс с "реальным" кодом. Вы могли даже использовать его для:: кашель:: генерируйте контекстное меню в non-oo системе контекстного меню:: кашель::. Не то, чтобы я когда-либо делал бы что-либо так хромое.

Редактирование: зафиксированная круглая скобка, которой не соответствуют, и расширенный пример

1
ответ дан 4 revs 23 November 2019 в 20:20
поделиться

Найденный в объявлениях, к большому количеству беспорядка:

NON_ZERO_BYTE         Fixed(8)  Constant('79'X),

Найденный позже:

IF WORK_AREA(INDEX) = ZERO_BYTE THEN  /* found zero byte */ 
   WORK_AREA(INDEX) = NON_ZERO_BYTE ; /* reset to nonzero*/
1
ответ дан 2 revs, 2 users 87% 23 November 2019 в 20:20
поделиться

Игровая Мудрость Программирования AI имеет главу, где макросы использовались для создания язык сценариев для конечных автоматов.

, Так как книга и код защищены авторским правом материал, вот книжная ссылка Google к странице, детализирующей макросы (Получающийся язык сценария может быть найден на странице 324.)

8
ответ дан 4 revs, 3 users 63% 23 November 2019 в 20:20
поделиться

См. этот ответ о том, как коллега-дислексик облегчил себе жизнь с помощью обычного файла заголовка, наполненного такими вещами, как #define fasle false .

2
ответ дан 23 November 2019 в 20:20
поделиться

Это взято из популярной программы с открытым исходным кодом. Фактически, это делает некоторые части кода более читабельными, скрывая уродливое наследие.

#define EP_STATUS    CASTLING][(BOARD_FILES-2)
#define HOLDINGS_SET CASTLING][(BOARD_FILES-1)

Думаю, здесь нет ничего плохого, просто мне это смешно.

http://git.savannah.gnu.org/cgit/xboard.git/tree/common.h

2
ответ дан 23 November 2019 в 20:20
поделиться
switch (device_id)
{
#ifndef PROD_1
#ifndef PROD_2
#ifdef PROD_3
  case ID_1:
#endif

#ifdef PROD_4

#ifdef PROD_5
  case ID_2:
  case ID_3:
  case ID_4:
#elif defined(PROD_4)
#ifndef PROD_6
  case ID_1:
#endif // PROD_6
  case ID_5:
#endif

  case ID_6:
#endif

#ifdef PROD_7
  #ifndef PROD_8
    case ID_7:
  #endif
#endif

(имена изменены для защиты не очень невинных)

Обратите внимание, что мы еще даже не дошли до какого-либо кода, это просто для того, чтобы добраться до первого фактического бита кода. На самом деле это происходит (почти, но не точно таким же образом) для нескольких функций, каждая из которых, в конечном итоге, имеет только 4 возможных варианта (которые также в основном копируют / вставляют с небольшими вариациями и собственными #ifdef).

5
ответ дан 23 November 2019 в 20:20
поделиться

В Lucent я однажды взглянул на исходный код исходной оболочки Unix Стива Борна и обнаружил, что он использовал препроцессор C, чтобы C выглядел как Паскаль или Алгол. Часть, относящаяся к операторам if, выглядела так:

#define IF   if (
#define THEN ) {
#define ELSE } else {
#define ELIF } else if (
#define FI   ; }

Мой друг сказал мне, что в середине 1990-х он немного отремонтировал ее, и она осталась прежней. (Здесь для нас есть урок консервативности, присущей кодовой базе.)

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

Обновление: Согласно статье Bourne Shell в Википедии, макросы придавали ему вид Algol 68 . И здесь полный набор макросов !

7
ответ дан 23 November 2019 в 20:20
поделиться

Однажды я собрал этот ужасающий код на C ++, который использовал макросы, чтобы перехватить функции в таблице импорта DLL.


#define ARGLIST(...) __VA_ARGS__

#define CPPTYPELESSARG(typelessParams) thisptr, typelessParams
#define CPPTYPEDARG(typedParams) void* thisptr, typedParams
#define CPPTYPELESSNOARG thisptr
#define CPPTYPEDNOARG void* thisptr

#define CPPHOOKBODY(hookName, params) void *thisptr; \
    __asm { mov thisptr, ecx } \
    return On##hookName ( params );


#define CHOOKBODY(hookName, typelessParams) return On##hookName( typelessParams );

#define CPPHOOK(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
    HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, CPPTYPEDARG(typedParams), typelessParams, \
    typedParams, __thiscall, __stdcall, CPPHOOKBODY(hookName, CPPTYPELESSARG(typelessParams)))

#define CPPHOOKNOARG(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
    HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, CPPTYPEDNOARG, typelessParams, \
    typedParams, __thiscall, __stdcall, CPPHOOKBODY(hookName, CPPTYPELESSNOARG))

#define CDECLHOOK(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
    HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams, \
    typedParams, __cdecl, __cdecl, CHOOKBODY(hookName, typelessParams))

#define CDECLFUNC(name, address, returnType, args) \
    typedef returnType (__cdecl *name##Ptr)(args); \
    name##Ptr name = (name##Ptr) address;

#define CPPFUNC(name, address, returnType, args) \
    typedef returnType (__thiscall *name##Ptr)(void* thisptr, args); \
    name##Ptr name = (name##Ptr) address;

#define STDFUNC(name, address, returnType, args) \
    typedef returnType (__stdcall *name##Ptr)(args); \
    name##Ptr name = (name##Ptr) address;

#define STDHOOK(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
    HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams, \
    typedParams, __stdcall, __stdcall, CHOOKBODY(hookName, ARGLIST(typelessParams)))

#define HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams, hookParams, fnPtrCall, hookCall, hookBody) \
        typedef returnType (fnPtrCall *##hookName##OrigPtr )( typedParams ); \
        class hookName : public IHook \
        { \
        public: \
            typedef hookName##OrigPtr func_type; \
        private: \
            static void* m_origFunction; \
            static bool m_bModifyImport; \
            static std::string m_lib; \
            static std::string m_importFunc; \
            static std::string m_sHookName; \
            static returnType hookCall hookName##FnHook ( hookParams ) \
            { \
                hookBody \
            } \
            static bool ImplIsModifyImport() { return hookName::m_bModifyImport; } \
            static void ImplSetModifyImport(bool bModify) { hookName::m_bModifyImport = bModify; } \
            static const std::string& ImplGetLibName() { return hookName::m_lib; } \
            static const std::string& ImplGetImportFunctionName() { return hookName::m_importFunc; } \
            static void ImplSetOriginalAddress(void* fn) { hookName::m_origFunction = fn; } \
            static void* ImplGetOriginalAddress() { return hookName::m_origFunction; } \
            static returnType On##hookName ( typedParams ); \
            static void* ImplGetNewAddress() { return hookName::##hookName##FnHook; } \
            static const std::string& ImplGetHookName() { return hookName::m_sHookName; } \
        public: \
            hookName() \
            { \
                InjectHookRef.AddHook((IHook*)this); \
                hookName::m_lib = importLib; \
                hookName::m_importFunc = importFunc; \
                hookName::m_sHookName = #hookName; \
                hookName::m_origFunction = NULL; \
                hookName::m_bModifyImport = true; \
            } \
            virtual bool IsModifyImport() const { return hookName::ImplIsModifyImport(); } \
            virtual void SetModifyImport(bool bModify) { hookName::ImplSetModifyImport(bModify); } \
            virtual const std::string& GetHookName() const { return hookName::ImplGetHookName(); } \
            virtual const std::string& GetLibName() const { return hookName::ImplGetLibName(); } \
            virtual const std::string& GetImportFunctionName() const { return hookName::ImplGetImportFunctionName(); } \
            virtual void* GetOriginalAddress() const { return hookName::ImplGetOriginalAddress(); } \
            virtual void* GetNewAddress() const { return hookName::ImplGetNewAddress(); } \
            virtual void SetOriginalAddress(void* fn) { hookName::m_origFunction = fn; } \
            static func_type GetTypedOriginalAddress() { return reinterpret_cast(hookName::m_origFunction); } \
        }; \
        void* hookName::m_origFunction = NULL; \
        bool hookName::m_bModifyImport = false; \
        std::string hookName::m_lib; \
        std::string hookName::m_importFunc; \
        std::string hookName::m_sHookName; \
        static hookName g##hookName##Inst;

Что, в свою очередь, позволило мне сделать это:

 CPPHOOK (gIH , "SimEngine.dll", " ? AddEntity @ Player @@ UAEXPAVEntity @ @@ Z", PlayerAddEntity, void, void * ent, ent); 

/ * Вызывается, когда движок вызывает Player :: AddEntity (entity) * / void PlayerAddEntity :: OnPlayerAddEntity (void * thisptr, void * ent) { беззнаковый int id = getPlayerID (thisptr);

gIH.GetLog()->Info("Player %d adding entity %s.", 
    getPlayerID(thisptr), getEntityName(ent));

gPlayers[id] = thisptr;

/*if( id == 2 && gPlayers[1] && gPlayers[2] )
    EntitySetOwner::GetTypedOriginalAddress() (ent, gPlayers[1]);*/
//gEnts[ent] = Entity(ent, Vector3f());

PlayerAddEntity::GetTypedOriginalAddress() (thisptr, ent);

}

2
ответ дан 23 November 2019 в 20:20
поделиться
#define interface struct

в некоторых заголовках Optima ++ (Optima ++ является / была IDE Watcom / Powersoft I пришлось работать с).

4
ответ дан 23 November 2019 в 20:20
поделиться

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

Это действительно великолепно ИМХО, как вы можете получить что-то подобное только с помощью sprintf, который затем требует выделения ресурсов и еще много чего, плюс, вся работа полностью выполняется препроцессором

// Macro: Stringize
//
//      Converts the parameter into a string
//
#define Stringize( L )          #L


// Macro: MakeString
//
//      Converts the contents of a macro into a string
//
#define MakeString( L )     Stringize(L)


// Macro: $LINE
//
//      Gets the line number as a string
//
#define $LINE                   MakeString( __LINE__ )


// Macro: $FILE_POS
//
//      Gets the current file name and current line number in a format the Visual Studio
//      can interpret and output goto
//
// NOTE: For VS to properly interpret this, it must be at the start of the line (can only have whitespace before)
//
#define $FILE_POS               __FILE__ "(" $LINE ") : "

Другой, который я не люблю использовать, но считаю чрезвычайно полезным, делает что-то подобное, что в основном позволяет я для быстрого создания шаблонов с переменным числом параметров шаблона

#define TEMPLATE_DEFS    typename ReturnType
#define TEMPLATE_DECL   ReturnType
#define FUNCTION_PARAMS void
#define FUNCTION_PASS   
#define GENERIC_CALLBACK_DECL_NAME      CallbackSafePointer0
#include "Callback.inl"

#define TEMPLATE_DEFS   typename ReturnType, typename P1
#define TEMPLATE_DECL   ReturnType, P1
#define FUNCTION_PARAMS P1 param1
#define FUNCTION_PASS   param1
#define GENERIC_CALLBACK_DECL_NAME      CallbackSafePointer1
#include "Callback.inl"

#define TEMPLATE_DEFS   typename ReturnType, typename P1, typename P2
#define TEMPLATE_DECL   ReturnType, P1, P2
#define FUNCTION_PARAMS P1 param1, P2 param2
#define FUNCTION_PASS   param1, param2
#define GENERIC_CALLBACK_DECL_NAME      CallbackSafePointer2
#include "Callback.inl"

#define TEMPLATE_DEFS   typename ReturnType, typename P1, typename P2, typename P3
#define TEMPLATE_DECL   ReturnType, P1, P2, P3
#define FUNCTION_PARAMS P1 param1, P2 param2, P3 param3
#define FUNCTION_PASS   param1, param2, param3
#define GENERIC_CALLBACK_DECL_NAME      CallbackSafePointer3
#include "Callback.inl"

// and so on...

Хотя это делает ужасным читать "Callback.inl", это полностью исключает переписывание того же кода с другим числом аргументов. Я также должен упомянуть, что "Callback.inl" #undefs все макросы в конце файла, следовательно, сами макросы победили.

1
ответ дан 23 November 2019 в 20:20
поделиться

Все, что использует sendmail и его магический синтаксис конфигурации

2
ответ дан 23 November 2019 в 20:20
поделиться

Я добавляю еще один, который со временем начал меня раздражать:

#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0]))

И это, если они все поняли правильно; Я видел версии со всеми возможными перестановками скобок или без них. Я видел, как он определен дважды в одном и том же файле заголовка.

В основном мой аргумент применим к Windows (хотя я предполагаю, что другие SDK ОС имеют нечто подобное), где почти каждый, кажется, чувствует необходимость определить этот макрос в своем проекте. заголовок, и я не понимаю, почему.

WinNT.h (который входит в состав Windows.h) определяет очень хорошую версию, которая заставляет некоторые шаблоны voodoo вызывать ошибки времени компиляции , если вы передаете тип указателя вместо массива.

Конечно, если вы создаете программу на языке C, все возвращается к тому, что я написал выше,

2
ответ дан 23 November 2019 в 20:20
поделиться
#define unless(cond) if(!cond)
#define until(cond) while(!cond)

Используется:

unless( ptr == NULL) 
    ptr->foo();
3
ответ дан 23 November 2019 в 20:20
поделиться

В то время казалось хорошей идеей "передать" макрос как аргумент в другой макрос. (Я просто не мог вынести мысли о том, чтобы определять список значений в нескольких местах. ) Код здесь надуманный (и не очень мотивирующий), но дает вам идею:

#define ENUM_COLORS(CallbackMacro) \
    CallbackMacro(RED)   \
    CallbackMacro(GREEN) \
    CallbackMacro(BLUE)  \
    // ...

#define DEFINE_COLOR_TYPE_CALLBACK(Color) \
    Color,

enum MyColorType {
    ENUM_COLORS(DEFINE_COLOR_TYPE_CALLBACK)
};

void RegisterAllKnownColors(void)
{
#define REGISTER_COLOR_CALLBACK(Color) \
    RegisterColor(Color, #Color);

    ENUM_COLORS(REGISTER_COLOR_CALLBACK)
}

void RegisterColor(MyColorType Color, char *ColorName)
{
    // ...
}
1
ответ дан 23 November 2019 в 20:20
поделиться
#define FLASE FALSE

Программист был плохим машинистом, и это была его самая частая ошибка.

4
ответ дан 23 November 2019 в 20:20
поделиться

Это не макрос C, но ...

Много лет назад у меня была забавная задача портировать оригинальный Transport Tycoon с ПК на Mac. Версия для ПК была полностью написана на ассемблере, поэтому нам пришлось пройти через весь исходный код и сначала перенести его на C-код ПК, а затем перенести его на Mac. Большая часть кода была в порядке, даже местами с объектной ориентацией. Однако система визуализации мира была невероятной. Для всех, кто не играл в игру, мир может быть просмотрен на одном из трех уровней увеличения. Код для этого был примерно таким:

macro DrawMacro <list of arguments>
   a couple of thousand lines of assembler with loads of conditionals
   based on the macro arguments

DrawZoomLevel1:
   DrawMacro <list of magic numbers>

DrawZoomLevel2:
   DrawMacro <list of more magic numbers>

DrawZoomLevel3:
   DrawMacro <list of even more magic numbers>

Мы, должно быть, использовали немного старую версию MASM, поскольку макрос вызывал сбой ассемблера, когда мы пытались его собрать.

Skizz

1
ответ дан 23 November 2019 в 20:20
поделиться

«Технический менеджер», который раньше работал кодером, ввел следующие замечательные макросы в наш проект C ++, потому что он думал, что проверка на NULL значений в подпрограммах синтаксического анализа DOM было просто слишком много работы:

TRYSEGV
CATCHSEGV

Внутри они использовали setjmp , longjmp и обработчик сигналов для SIGSEGV , чтобы имитировать возможность «поймать» segfault.

Конечно, ничего в коде не сбрасывает указанную точку перехода, когда код выходит за пределы области действия исходного TRYSEGV вызова макроса, поэтому любой segfault в коде вернется к (теперь недействительному) указателю jump_env .

Код тут же умрет,но не раньше, чем уничтожить стек программы и сделать отладку более или менее бессмысленной.

9
ответ дан 23 November 2019 в 20:20
поделиться
#define "CR_LF" '\r'

Это на время меня чертовски смутило!

2
ответ дан 23 November 2019 в 20:20
поделиться

Сопрограммы (также известные как потоки без стека) в C. :) Это злой обман.

#define crBegin static int state=0; switch(state) { case 0:
#define crReturn(i,x) do { state=i; return x; case i:; } while (0)
#define crFinish }
int function(void) {
    static int i;
    crBegin;
    for (i = 0; i < 10; i++)
        crReturn(1, i);
    crFinish;
}

int decompressor(void) {
    static int c, len;
    crBegin;
    while (1) {
        c = getchar();
        if (c == EOF)
            break;
        if (c == 0xFF) {
            len = getchar();
            c = getchar();
            while (len--)
            crReturn(c);
        } else
        crReturn(c);
    }
    crReturn(EOF);
    crFinish;
}


void parser(int c) {
    crBegin;
    while (1) {
        /* first char already in c */
        if (c == EOF)
            break;
        if (isalpha(c)) {
            do {
                add_to_token(c);
        crReturn( );
            } while (isalpha(c));
            got_token(WORD);
        }
        add_to_token(c);
        got_token(PUNCT);
    crReturn( );
    }
    crFinish;
}
6
ответ дан 23 November 2019 в 20:20
поделиться

Худшее, что я видел, - это в моем текущем проекте, где очень много случаев:

#if PROGRAMA
     .
     .
    if(...)
    {
     .
     .
     .
#else
    .
     .
    if(...)
    {
     .
     .
     .
#endif
     }

Да, он закрывает 2 открытия одним закрытием.

3
ответ дан 23 November 2019 в 20:20
поделиться

Код NFS в BSD-ядрах использует GoTo между макросами. Это все еще используется, и код на самом деле работает. Я знаю из нескольких человек, которые пытались убрать его, но все они сдавались через некоторое время - это просто грязно.

Вы можете увидеть это здесь: http://www.openbsd.org/cgi-bin/cvsweb/src/sys/nfs/nfsm_subs.h?rev=1.43

1
ответ дан 23 November 2019 в 20:20
поделиться

Прошлый работодатель обнаружил, что на современных Unix-системах нет реализаций BASIC-PLUS, поэтому они попытались реализовать его заново, используя макросы препроцессора C:

#define IF if(
#define THEN ) {
#define ENDIF }
#define GOTO goto L

... и т.д.

Ужасно.

2
ответ дан 23 November 2019 в 20:20
поделиться

Что-либо, что использует Маркерный оператор конкатенации ##. Я видел, что это раньше взламывало вместе psudo-шаблонные системы в C++ и других ужасных вещах. Худшая вещь об использовании его состоит в том, как невозможно загадочный Ваши сообщения об ошибках становятся.

я видел одно хорошее использование для него как бы то ни было. Был макро-#MONITOR_COMPONENT (имя класса), которое генерировало классы во время компиляции, которые наследуются предопределенному классу монитора и имени класса, и это автозарегистрировалось бы в singleton-классе, который использовался для контроля каждого компонента.

это работало? Да, был это самый хороший способ сделать его.. вероятно, нет.

-1
ответ дан ErgoSum 23 November 2019 в 20:20
поделиться
#define protected private

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

0
ответ дан Greg Domjan 23 November 2019 в 20:20
поделиться

Любой макрос, в котором используется оператор конкатенации токенов ## .

Я видел один, с которым мой коллега имел удовольствие работать. Они пытались создать индивидуальную реализацию интернирования строк, поэтому они повторно реализовали строки, используя огромное количество макросов, которые (конечно) не работали должным образом. Попытка понять, что это такое, заставила мои глаза взорваться из-за разбросанных ## .

0
ответ дан 23 November 2019 в 20:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: