2014-12-28 7 views
1

Если я использую некоторые макрокоманды в пространстве имен, то почему они должны работать вне пространства имен? Проверьте этот код, например:Почему определения внутри пространства имен C++ работают вне пространства имен?

#include <bits/stdc++.h> 

namespace foo { 
    #define a x*2 

    int f(int x) { 
     return a; 
    } 
} 

int main() { 
    int a = 50; 
    std::cout << a << endl; 

    std::cout << foo::f(4) << endl; 

    return 0; 
} 

Здесь я никогда не писал, используя пространство имен foo. Но этот код не скомпилируется, потому что при попытке объявить int a он будет нарушен ранее определенным a. Но почему это должно произойти?

ответ

6

«... при попытке объявить int a, это нарушает ранее определенный a. Но почему это должно произойти?»

#define утверждение интерпретируется C/C++ препроцессором, который не имеет понятия о пространствах имен (или любой другой C++ языковые конструкции).

Если вы хотите ограничить степень определения, использовать #undef директивы:

namespace foo { 
    #define a x*2 

    int f(int x) { 
     return a; 
    } 
    #undef a 
// ^^^^^^^^ 
} 
+0

re "или любые другие языковые конструкции C++", для использования в качестве условий '# if' препроцессор поддерживает подмножество выражений C. Стоит отметить, что эти выражения не включают в себя литералы 'false' и' true' C++. Тестирование только сейчас для практики, g ++ принимает их, но Visual C++ этого не делает. –

+0

Этот ответ верный, но я хотел бы расширить терминологию. Шаг препроцессора возникает перед разбором и, с технической точки зрения, обрабатывает отдельный язык. IE все директивы, такие как '# include', разворачиваются, а затем результирующий предварительно обработанный источник анализируется и создается AST (абстрактное исходное дерево). Вы можете выгрузить предварительно обработанный вывод, вызвав 'gcc -E'. –

+0

@os_ Это достаточно ясно (и, по крайней мере, принято) ИМХО. Вы можете попробовать изменить, чтобы улучшить. –

4

Предварительно процессор ничего особенности языка высокого уровня, такие как пространство имена или обзорные не знает. Он просто ищет строки, начинающиеся с #, а затем просто заменяет текст. Это одна из причин, почему использование препроцессора для чего-либо, кроме #include, или файловых охранников опасно на C++.

3

#define не относится к области C++. Нет такой вещи, как "local" #define. Он будет действовать до тех пор, пока не будет #undef-ed.

namespace foo { 
    #define a x*2 

    int f(int x) { 
     return a; 
    } 
    #undef a    <<<<<<<<<<<<<<<<<<<<< 
} 
1

Препроцессор C в значительной степени является языком его собственного. Он выполняется первым. Макросы создают код, который передается в настоящий компилятор C/C++. Всякий раз, когда вы используете макросы, всегда помните, что макросы превзошли все, даже фигурные скобки. Только другая директива препроцессора, например #undef, может остановить макрос.

Кстати, вы можете использовать только препроцессор C только в любом текстовом файле.

Смежные вопросы