2009-02-05 7 views
57

Я использую полное имя переименования внутри метода в одном из моих классов. Но я получаю предупреждение о компиляторе, которое сообщает «Предупреждение C4482: используется нестандартное расширение: enum« Foo »используется в квалифицированном имени«. В C++ нам нужно использовать перечисления без квалифицированного имени? Но ИМО, что выглядит уродливо.Использование enum внутри типов - Предупреждение компилятора C4482 C++

Любые мысли?

+5

у вас есть Java опыт я думаю;) – hhafez

+1

:) Да. Java и C#. Infact, это единственная функция, которую я чувствовал уродливым на C++ по сравнению с этими двумя. –

+6

Если вам нужен такой синтаксис, вы могли бы просто создать образец пространства имен {enum {BLAH0, BLAH1}}, а затем просто ссылаться на него как на образец :: BLAH0 – BigSandwich

ответ

53

Да, перечисления не создают новое «пространство имен», значения в перечислении доступны непосредственно в окружении. Таким образом, вы получаете:

enum sample { 
    SAMPLE_ONE = 1, 
    SAMPLE_TWO = 2 
}; 

int main() { 
    std::cout << "one = " << SAMPLE_ONE << std::endl; 
    return 0; 
} 
11

Да. Концептуально перечисление определяет тип и возможные значения этого типа. Хотя кажется естественным, определить enum foo { bar, baz };, а затем обратиться к foo::baz - это то же самое, что и ссылка на int::1.

+0

, но вы можете использовать foo :: baz (и получить предупреждение), вы фактически не можете использовать int :: 1 –

+3

@ Simón: Вы получаете это предупреждение только в Visual Studio, которое реализует его как расширение компилятора. GCC нет; если вы не компилируете C++ 11 (где это законный синтаксис). –

35

Чтобы сделать его чистым, замените:

enum Fruit { 

    ORANGE = 0, 
    BANANA = 1 

}; 

с

namespace Fruit { 

    enum { //no enum name needed 

     ORANGE = 0, 
     BANANA = 1 

    }; 

}; 

... 

int f = Fruit::BANANA; //No warning 
+2

Мне нравится этот подход. (Я тоже прихожу с Java.) Я не понимаю мудрости именных переписных имен. Мне было бы интересно узнать причину. –

+8

Мне не нравится этот подход, потому что тип переменной не предполагает, что это перечисление. – qub1n

14

Хотя СТГ действительно отвечает на вопрос, он не обращался, как я всегда перечислений. Несмотря на то, что они являются более или менее именами для чисел, я всегда использовал их для определения типов, которые могут иметь только определенные значения.

Если перечисление является частью класса, то, что помогает потребителям четко определить ссылку на перечисление:

class Apple { 
    enum Variety { 
    Gala, 
    GoldenDelicious, 
    GrannySmith, 
    Fuji 
    } 
    ... 
}; 

Тогда потребители могли бы заявить о экземплярах перечисления, передать в качестве параметров, и квалифицировать их при обращении один из типов.

unsigned int GetCountOfApples(Apple::Variety appleVariety); 
... 
fujiCnt = GetCountOfApples(Apple::Fuji); 

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

namespace Color { 
    enum ColorEnum { 
    Blue, 
    Red, 
    Black 
    }; 

Теперь с помощью перечисления и значения будут работать, как:

Color::ColorEnum firstColor = Color::Blue; 
Color::ColorEnum secondColor = Color::Red; 

if(firstColor == secondColor) 
.... 

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

BananaColorEnum banCol = BananaColor::Yellow; 
TomatoColorEnum tomCol = TomatoColor::Yellow; 
7

Чистейшая способ я нашел, чтобы сделать это определение перечисления в качестве такого

namespace Samples 
{ 
    enum Value 
    { 
     Sample1, 
     Sample2, 
     Sample3 
    }; 
} 
typedef Samples::Value Sample; 

Тогда в функции и определения переменных можно использовать ЬурейеЕ:

void Function(Sample eSample); 
Sample m_eSample; 

И в вашем .cpp-файле вы можете использовать пространство имен для назначения переменных:

void Function(Sample eSample) 
{ 
    m_eSample = Samples::Sample1; 
    eSample = Samples::Sample2; 
} 
8

namespace Company 
{ 
    typedef int Value; 
    enum 
    { 
     Microsoft= 0, 
     APPLE = 1, 
    }; 
}; 

namespace Fruit 
{ 
    typedef int Value; 
    enum 
    { 
     ORANGE = 0, 
     BANANA = 1, 
     APPLE = 2, 
    }; 
}; 

... 

Fruit::Value f = Fruit::BANANA; //No warning 
Company::Value f = Company::APPLE; //is different value then Fruit::APPLE 

Это работает с компилятором GCC и MS и Mac.Преимущество состоит в том, что вы можете использовать оператор пространства имен и передавать конфликты. Небольшой недостаток заключается в том, что вместо Fruit вам нужно написать Fruit :: Value. он более полезен в большом проекте, когда вы не знаете, что перечислены в другом классе.

Если это возможно, используйте C++ 11, это намного проще, потому что тогда возможно синтаксис enum :: namespace.

+0

Ваше сообщение было бы более ценным, если бы вы могли добавить к нему какое-то объяснение. :) – ForceMagic

+2

У меня есть описание. – qub1n

+0

Очень хороший ответ. Простой и чистый. – deeJ

1

Лично я думаю, что это ошибка компилятора. Я использую C++ много времени. К сожалению, в OP нет образца кода. Толкование перечисления людьми Java было фактически правильным iMO. Шахта, как это было ...

class Foo { 
    enum tMyEnum { eFirstVal = 0, eSecondVal = 1}; 
    // ... 
    tMyEnum m_myVal; 
}; 
void Foo::MyMethod() { 
    if(m_myVal == tMyEnum::eFirstVal) { 
// ... 
    } 
} 

Я также попробовал, Foo :: tMyEnum :: eFirstVal. Без квалификаторов все скомпилировано.

0

У меня была такая же проблема, и я еще не использую C++ 11. Я тоже предпочитаю полностью квалифицированные пространства имен.

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

#pragma warning(disable : 4482)