2009-11-12 2 views
2

Есть ли способ на C++ определить вложенные макросы/константы внутри класса, аналогично вложенным typedefs или метод для получения аналогичных функций? Мотив, как правило, заключается в том, что макросы используются шаблонами.Вложенные макросы C++?

class SomeClass 
{ 
public: 
    #define SomeConstant 123 
}; 

int x=SomeClass::SomeConstant; 

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

ответ

8

Вы не можете делать то, что хотите, с помощью макросов. Макросы не имеют понятия обзора.

Но для простых значений int вы можете делать то, что хотите, с перечислениями.

class SomeClass 
{ 
public: 
    enum { 
     SomeConstant=123 
     }; 
}; 

int x=SomeClass::SomeConstant; 

Полностью название области видимости значения, но не пространство, занимаемое для него, даже в отладочной версии - Вы не могли бы взять его адрес, если вы хотите.

+0

+1 для использования перечисления в качестве константы. Я получаю тепло для «злоупотребления» перечислениями, и я не думаю, что это так. – Michael

2

Предварительные процессоры Macro обычно не имеют представления о контексте языка; поэтому они не знают, что «класс» делает «гнездом внутри класса», не имеет смысла в первую очередь.

Для чего вы хотите использовать static const или использовать полное имя (предполагая, что препроцессор разрешает двоеточие в именах макросов, а не на 100% уверен в этом), хотя это не позволит вам наследовать константу на производном классы:

#define SomeClass::SomeConstant 123 
+0

Использование полного имени (если оно разрешено) не поможет, когда шаблоны выбрасываются в микс –

+0

':' не указано _ в имени макроса. –

2

Макросы полностью игнорируют область действия - они расширены до компиляции C++. Ты просто не можешь этого сделать.

Использование static const часто приводит к отсутствию переменной - компилятор рассматривает ее как константу.

0

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

1

Вы можете сделать это с помощью шаблонов:

 
template < int someConstant = 123 > class SomeClass 
{ 
public: 
    void outputConstant() { cout << "We think the answer is:" << someConstant; } 
} 

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

 
int main(int argc, char *argv) 
{ 
    SomeClass<123> myInstance; 
} 

Я знаю, что другие объяснил бит о макросах, но позвольте мне добавить: #define обрабатывается препроцессором, а не компилятором. В стандарте есть раздел, называемый «фазами перевода», который объясняет это более подробно, но для вашего вопроса дело в том, что макросы оцениваются до того, как класс даже скомпилирован, а область, в которой происходит #define, неизвестна.

Авторитетная книга по этому вопросу (программирование с использованием шаблонов на этапе компиляции) - Modern C++ Design: Generic Programming and Design Patterns Applied, by Andrei Alexandrescu.

0

«Статические элементы - физические переменные».

Что против этого? Единственная причина возражать против этого - использование памяти. Но поскольку элемент статичен, память будет занята только один раз с предполагаемым контентом.

Напротив, с макросом в конкурсе будет присутствовать в каждом месте использования в двоичном формате.

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

+0

Хм. И со статикой АДРЕС будет присутствовать в каждом единственном месте использования_ в двоичном формате. Итак, если это байт, мы говорим о ... –

+0

В случае 'char' (или другого небольшого интегрального типа) вы можете определить его в объявлении класса, и он будет снова вставлен в очередь. – xtofl

6

Значения констант, объявленные и определенные на месте, являются именно тем, что вам нужно здесь: компилятор может и будет оптимизировать их полностью, чтобы они в итоге оказались такими же, как при использовании #define в первую очередь, но с преимуществами строгого обзора.

class SomeClass { 
    public: 
    static const int someValue = 10; 
}; 

Это не занимает лишнего места - для хранения «someValue» памяти не выделяется. Вы можете это доказать: если вы попытаетесь использовать «someValue» в качестве реального объекта (т. Е. Попытаетесь получить его адрес), то компоновщик скажет вам, что он не определен.

+1

Строго говоря, есть еще одна деталь, если вы используете переменные 'static const': вы должны иметь определение' const int SomeClass :: someValue; 'где-то (ровно один раз, но только если вы в противном случае используете участника), или вы полагаетесь на неопределенное поведение. Я знаю, что это не проблема на самом деле, компоновщик все еще может выбросить хранилище, если он не используется, и правило в значительной степени игнорируется (и Stroustrup считает это «неправильной»), но это правила. C++ 03 9.4.2/4 (http://stackoverflow.com/questions/370283/why-cant-i-have-a-non-integral-static-const-member-in-a-class/370433# 370433) –

+1

Очень верно: и иногда я обнаружил, что при передаче «someValue» на что-то, что принимает шаблонную ссылку (например, тестовые жгуты), компилятор хочет взять адрес someValue и поэтому нуждается в определении. Однако обходным путем для этого является использование унарного оператора plus, поэтому в моем случае я буду делать ASSERT_EQUALS (+ SomeClass :: someValue, expr()); –

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