2013-04-13 2 views
0

Я пытаюсь сделать что-то вроде:Макро метапрограммированием ужас

custommacro x; 

, который будет расширяться в:

declareSomething; int x; declareOtherthing; 

даже возможно ли это?

Я уже обманул его с помощью operator=, чтобы вести себя так, но это невозможно сделать с объявлениями.

+1

Что вы хотите объявить? Могут быть и другие способы. Также 'custommacro (x);' является очевидным способом. – Pubby

+0

Все дело в том, что у них нет этих скобок вокруг 'x'. –

+0

невозможно, на мой взгляд, это очень сложно и тонко. Вы должны использовать() и все кепки, чтобы сделать очевидным то, что действительно происходит. Попытка скрыть вещи или сделать «волшебство» почти всегда усложняет ситуацию. Просто выполните 'CUSTOMMACRO (x)'; –

ответ

6

Вы можете игнорировать скобки до тех пор, пока вы готовы принять два дополнения:

  1. весь код должен быть обернут в блок макро
  2. там должно быть что-то после эхо директивы

eg Таким образом:

#define LPAREN (
#define echo ECHO_MACRO LPAREN 
#define done) 

#define ECHO_MACRO(X) std::cout << (X) << "\n" 

#define DSL(X) X 

... 
DSL(
    echo "Look ma, no brains!" done; 
) 
... 

Причины этого:

  1. Там нет никакого способа сделать функцию, как макрос расширения без скобок. Это всего лишь базовое требование макроязыка; если вы хотите что-то еще изучить другой макропроцессор
  2. Поэтому нам нужно вставить круглые скобки; в свою очередь, мы должны иметь что-то после директивы, как в done макро, который будет расширяться в форме containinf необходимых близких Paren
  3. К сожалению, поскольку echo ... done форма не выглядит как вызов макроса для препроцессора, он не был отмечен для расширения, когда препроцессор вошел в него, и вставили ли мы парны или нет, это не имеет значения.Поэтому использование echo ... done приведет к выходу вызова ECHO_MACRO в текст
  4. Текст повторно сканируется, помечен для расширения и снова разворачивается, когда он является аргументом функционально-подобного макроса, поэтому обертывание всего блока блочным макросом (здесь это DSL) заставят вызов ECHO_MACRO быть расширен на этом ReScan прохода (DSL ничего не делает с результатом: она существует только, чтобы заставить пересканирование)
  5. Нам нужно, чтобы скрыть ( в расширении echo за простым макросом LPAREN, поскольку в противном случае несогласованная скобка в макрообъекте путает препроцессор

Если вы хотите создать целый предметно-ориентированный язык для таких команд, можно также уменьшить количество done команд, делая ядро ​​команды еще более громоздким:

#define LPAREN (

#define begin NO_OP LPAREN 0 
#define done); 

#define echo); ECHO_MACRO LPAREN 
#define write); WRITE_MACRO LPAREN 
#define add); ADD_MACRO LPAREN 
#define sub); SUB_MACRO LPAREN 

#define NO_OP(X) 
#define ECHO_MACRO(X) std::cout << (X) << "\n" 
#define WRITE_MACRO(X) std::cout << (X) 
#define ADD_MACRO(D, L, R) (D) = (L) + (R) 
#define SUB_MACRO(D, L, R) (D) = (L) - (R) 

#define DSL(X) DSL_2 X 
#define DSL_2(X) X 

int main(void) { 
int a, b; 
DSL((
    begin 
     add a, 42, 47 
     sub b, 64, 50 
     write "a is: " 
     echo a 
     write "b is: " 
     echo b 
    done 
)) 
return 0; 
} 

В этой форме каждая команда заранее - предназначен для закрытия предыдущей команды, так что только последний нужен done; вам нужна линия begin, так что есть команда открытия первой реальной операции для закрытия, иначе параны будут несоответствовать.

Беспощадно, так как это намного проще в C, чем на C++, поскольку препроцессор C более мощный (он поддерживает __VA_ARGS__, которые очень важны для сложного макропрограммирования макросов).

Ах да, и еще одна вещь -

... пожалуйста никогда не сделать это в реальном коде.

+0

+1 для _пожалуйста никогда не делайте этого в реальной части кода ._. – mg30rg

2

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

Кроме того, о своем echo хака: это на самом деле очень просто с помощью операторов в C++:

#include <iostream> 

#define echo std::cout << 

int main() 
{ 
    echo "Hello World!"; 
} 

Но вы действительно не должны писать код, как это (то есть, используя макросы и psuedo-echo hack). Вы должны написать код, который соответствует синтаксису языка и семантике того, что вы пытаетесь сделать. Если вы хотите записать на стандартный вывод, используйте std::cout. Более того, если вы хотите использовать echo, сделайте функцию с именем echo, которая вызывает внутри себя std::cout, но не взламывает возможности языка, чтобы создать свой собственный.

1

Вы можете использовать расширение выражений оператора for-loop и GnuC.

#define MY_MACRO\ 
    FOR_MACRO(_uniq##__COUNTER__##name,{/*declareSomething*/ },{ /* declareOtherthing */ }) int 

#define FOR_MACRO(NAME,FST_BLOCK,SND_BLOCK)\ 
    for(int NAME = ({FST_BLOCK ;0;}); NAME<1 ; NAME++,(SND_BLOCK)) 

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