2015-10-14 10 views
0

Я предоставляю пример с разрешениями дисплея, но вопрос более общий.Как последовательно определять список опций для использования в качестве enum, int и string в одно и то же время?

Предположим, у нас есть следующие конфигурации: 640x480; 1024x768; 1600x900. Если они определены отдельно, это будет выглядеть примерно так:

std::string RESTR[] = { "640x480", "1024x768", "1600x900" }; 
struct Enum { enum ERes { _640x480, _1024x768, _1600x900 }; }; 
uint RES[][2] = { { 640, 480 }, { 1024, 768 }, { 1600, 900 } }; 

Это слишком подверженная ошибкам поддержка всех списков. Должно быть дан следующим образом (или по крайней мере что-то очень похожее):

Res( 640, 480) 
Res(1024, 768) 
Res(1600, 900) 

Класс Разрешения Казался бы, прекрасным решением, он ведет себя как строка, когда это необходимо, и возвращает значение, в других случаях использования. Но перед запуском приложения он не имеет перечислений. Для использования разрешений в разработке требуется магия времени компиляции, требуется препроцессор или определение шаблона. Как это можно решить?

Существует ли стандартный современный подход к решению этой проблемы?

+0

Пожалуйста, google «представление строки C++ enum» –

+0

Я могу определить строки и перечисления сразу, но представление int все еще существует. – renonsz

ответ

2

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

  1. Подход, основанный на variadic macro (вы можете написать свой собственный код или использовать Boost.Preprocessor библиотеки макросов).
  2. Подход, основанный на X-macro technique.

Второй подход подходит для вас, если вы используете C++ 03 или ниже (первый из них доступен, если вы используете C++ 11 или выше, или если ваш C++-компилятор поддерживает C99). Вот его описание:

  • Создать инклюдник без включают охрану (вы можете дать ему расширение, отличное от вашего обычного расширения файла заголовка, например inc) с именем Resolution и следующим содержанием:

    RESOLUTION( 640, 480) 
    RESOLUTION(1024, 768) 
    RESOLUTION(1600, 900) 
    
  • Определите свои массивы следующим образом:

    #define TO_STRING_LITERAL_(S) #S 
    #define TO_STRING_LITERAL(S) TO_STRING_LITERAL_(S) 
    #define STRING_RESOLUTION_(X, Y) X ## x ## Y 
    #define STRING_RESOLUTION(X, Y) TO_STRING_LITERAL(STRING_RESOLUTION_(X, Y)), 
    #define ENUM_RESOLUTION(X, Y) _ ## X ## x ## Y, 
    #define INT_RESOLUTION(X, Y) { X , Y }, 
    
    #define RESOLUTION(X, Y) STRING_RESOLUTION(X, Y) 
    std::string RESTR[] = 
    { 
    # include "Resolution.inc" 
    }; 
    #undef RESOLUTION 
    
    #define RESOLUTION(X, Y) ENUM_RESOLUTION(X, Y) 
    struct Enum 
    { 
        enum ERes 
        { 
    #  include "Resolution.inc" 
        }; 
    }; 
    #undef 
    
    #define RESOLUTION(X, Y) INT_RESOLUTION(X, Y) 
    uint RES[][2] = 
    { 
    # include "Resolution.inc" 
    }; 
    #undef 
    

Update:@rici предлагает в комментариях интересное упрощение STRING_RESOLUTION макросъемки:

#define STRING_RESOLUTION(X, Y) #X "x" #Y 

Это возможно потому, что ряд строковых литералов признан одним буквальным компилятором C++: "string1" "string2" "string3" == "string1string2string3".

+2

Для строки я бы предложил более простой '#define STRING_RESOLUTION (X, Y) #X" x "# Y'. В общем случае невозможно объединить строки ## - concat, и полезно помнить, что это почти никогда не нужно. – rici

+0

@rici Да, это хорошее упрощение. Спасибо. – Constructor

+0

Кажется, что трюк, которого мне не хватало, был 'undef', так что макрос' RESOLUTION' используется для нескольких целей. Очень хитрый и благодарю вас за то, что вы дали более широкий ответ на C++ 03! – renonsz

1

Если вы не состоите в браке с использованием enum, вы можете использовать что-то вдоль линий:

#define CONCAT2(A, B) A ## B 
#define CONCAT(A, B) CONCAT2(A, B) 

#define STR2(A) #A 
#define STR(A) STR2(A) 

#define DEFINE_RESOLUTION(ResClass, X, Y) \ 
    struct ResClass { \ 
     static const int val = CONCAT(0x, CONCAT(X, Y)); \ 
     static char const* toString() \ 
     { \ 
     return STR(CONCAT(X, CONCAT(x, Y))); \ 
     } \ 
     static int getX() { return (X); } \ 
     static int getY() { return (Y); } \ 
    }; 
DEFINE_RESOLUTION(Res1, 640, 480); 
DEFINE_RESOLUTION(Res2, 1024, 768); 

// Test the code 
#include <iostream>  

int getint() 
{ 
    return Res1::val; 
    // return Res2::val; 
} 

int main() 
{ 
    int v = getint(); 
    switch (v) 
    { 
     case Res1::val: 
     std::cout << Res1::getX() << "\n"; 
     std::cout << Res1::getY() << "\n"; 
     std::cout << Res1::toString() << "\n"; 
     break; 

     case Res2::val: 
     std::cout << Res2::getX() << "\n"; 
     std::cout << Res2::getY() << "\n"; 
     std::cout << Res2::toString() << "\n"; 
     break; 

     default: 
     std::cout << "Got default\n"; 

    } 
    return 0; 
} 

Выход:

640 
480 
640x480 

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

  • Нет связанных вопросов^_^