2016-09-12 5 views
0

내 프로젝트 열거 형 값에서 종종 로그 파일에 쓰거나 문자열로 유지해야합니다. 그래서, 다음 예에서와 같이 기능 ToString 및 StringToEnum를 제공 봤는데 : 내가 StringToEnum를 사용할 때 내가 쓰기 결국반환 유형에 따라 오버로드를 선택하는 방법

namespace Mine 
{ 
    enum class Color { red, green, blue }; 

    inline std::wstring ToString(Color c) 
    { 
     switch (c) 
     { 
     case Color::red: return L"red"; 
     case Color::green: return L"green"; 
     case Color::blue: return L"blue"; 
     default: THROW_MACRO("Unexpected value[{}] for enum[{}]", c, L"Color"); 
     } 
    } 

    inline void StringToEnum(const std::wstring& inEnumValueName, Color& out) 
    { 
     if (inEnumValueName == L"red") 
     { 
      out = Color::red; 
     } 
     else if (inEnumValueName == L"green") 
     { 
      out = Color::green; 
     } 
     else if (inEnumValueName == L"blue") 
     { 
      out = Color::blue; 
     } 
     else 
     { 
      THROW_MACRO("Unexpected value[{}] for enum[{}]", inEnumValueName, L"Color"); 
     } 
    } 
} 

:

Color c; 
StrintToEnum(L"red", c); 
// use c 

난 정말 선언 할 수 있도록하고 싶습니다 및 한 줄에 초기화 및 쓰기 :

auto c = ToEnum<Mine::Color>(L"red); 

내가 같이 ToEnum을 정의 헤더에 넣어 포함합니다 :

namespace CommonCode 
{ 
    template<class T> 
    T ToEnum(const std::wstring& enumValueName) 
    { 
     T value; 
     StringToEnum(enumValueName, value); 
     return value; 
    } 
} 

관련 StringToEnum 함수가 정의되지 않았기 때문에 ToEnum이 컴파일되지 않습니다.

코딩 할 수있는 유용한 방법이 있습니까? 또는 문자열에서 열거 형 값을 선언하고 초기화 할 때마다 두 줄의 코드를 작성해야 할 필요가 있습니까?

나는 ToEnum을 전문화하려고 시도했으나 열거 형을 정의하고있는 네임 스페이스를 닫고 CommonCode 네임 스페이스를 열고 추가 한 다음 원래 네임 스페이스로 다시 이동해야한다는 문제가있었습니다. 이것은 많은 타이핑이고 꽤보기 흉하게 보입니다.

(저는 Visual Studio 2015 Update 3을 사용하고 있으므로 컴파일 할 때 어떤 솔루션이든 선호 될 것입니다).

+0

왜 'StringToEnum'을 참조로 전달하지 않고'Color'를 반환 할 수 없는지 잘 모르겠습니다. – TartanLlama

+0

@TartanLlama 왜냐하면'Color' 만 가능하기 때문입니다. 다른 열거 형에 사용할 수 없습니다. –

+0

왜 'StringToEnum'이 색상 자체를 반환 할 수 없는지 확실하지 않습니다. b) ToEnum 템플릿 전에 선언 할 수없는 이유. – SergeyA

답변

1

StringToEnum은 실제로 Enum을 반환합니다. 그대로 사용하는 것이 다소 불쾌합니다. MSVC incorrectly implements 2 단계 템플릿 조회 이후 함수 템플릿 솔루션이 실패합니다. 그래서 대신 다른 유형을 StringToEnum에 전달하여 유형을 결정하는 데 사용할 수 있습니다.원래 예에서

template <class T> struct tag { }; 

: 가능한 한 명확하게하기 위해이 "뭔가"의 목적이 무엇인지, 우리는 그것을 자신의 유형을 만들거야 지금 때마다 당신을 그래서

inline Color StringToEnum(const std::wstring& inEnumValueName, tag<Color>) 
{ 
    if (inEnumValueName == L"red") 
    { 
     return Color::red; 
    } 
    else if (inEnumValueName == L"green") 
    { 
     return Color::green; 
    } 
    // etc. 
} 

즉 단지, E을 열거 형 문자열을 변환 할 :

: 일반적인 과부하로 단축 될 수

auto e = StringToEnum(str, tag<E>{}); 

#include <string> 

enum class Fail { err }; 
enum class Color { red,blue,green}; 

//generic template: causes error in compilation 
template<typename T> 
T enumToString(std::string s) 
{ 
    static_assert(sizeof(T) == -1,"no overload for enum"); 
} 

//specialization for Color 
template<> 
Color enumToString(std::string s) 
{ 
    if(s == "red") 
     return Color::red; 
    else if(s == "blue") 
     return Color::blue; 
    return Color::green; 
} 

int main() 
{ 

    auto c = enumToString<Color>("blue"); 
// auto e = enumToString<Fail>("e"); //this will cause a compiler error 
    return static_cast<int>(c); 
} 

그냥 당신이 필요로하는 각 열거의 템플릿을 전문 :

template <class T> 
inline T StringToEnum(const std::wstring& name) { 
    return StringToEnum(name, tag<T>{}); 
} 

auto e = StringToEnum<E>(str); 
0

다른 네임 스페이스가 있습니다. 템플릿 선언은 거의 정확하지만, StringToEnum을 알아야합니다.

namespace CommonCode { 
    template<class T> 
    T ToEnum(const std::wstring& enumValueName) { 
     T value; 

     // Notice the namespace here 
     Mine::StringToEnum(enumValueName, value); 
     return value; 
    } 
} 

내가 추천하는 것은 바로 직접 모든 기능을 인스턴스화하는 것입니다 : 당신은 단순히 당신이 기능을 사용할 때 네임 스페이스를 둘 필요가

template<class T> 
T toEnum(const std::string&); 

template<> 
Color toEnum<Color>(const std::string&) { 
    if (inEnumValueName == L"red") { 
     out = Color::red; 
    } 

    // ... 
} 

그것은 상용구를 제거하고 사용하자 당신의 당신이 원하는 것과 같은 기능을 제공하며, 올바른 구문으로 구현됩니다.

+1

고마워요,하지만이 말이 옳지는 않습니다. C++은 여기에 설명 된 바와 같이 인수 의존적 인 조회 때문에 다른 네임 스페이스에있는 경우에도 함수를 찾습니다. http://en.cppreference.com/w/cpp/language/adl –

+0

맞습니다. 나는 첫 번째 부분을 버렸다. –

0

당신은 템플릿 특수화를 사용할 수 있습니다. 나는 또한 특별한 구현이 없다면 실패 할 기본 구현을 추가했다.

관련 문제