2011-01-25 4 views
1

템플릿 프로그래밍 기술을 확장하려고하는데 적절한 해결책이없는 문제에 직면하고 있습니다. 이 템플릿은 좀 더 고급 템플릿 작업을 수행하기위한 개인 교육 실행 파일입니다.템플릿 프로그래밍에 대한 도움이 필요합니다.

목표 : 형식 문자열의 유형에 따라 모든 정수 유형 (sprintf 또는 swprintf 사용)을 문자열 또는 wstring으로 변환하기위한 템플릿을 작성하십시오. 오류 검사가 필요하지 않습니다 (현재는 현재 없음). 난 가변 형식의 문자 유형을 결정하기 위해 필요로하는 대 중 "%i" 또는 L"%i" int로서 기본 리터럴 값을 제공 할 필요

(const char*) NULL 또는 (const wchar_t*) NULL

문제는 형식이 지정된 경우이며 . 지금은 SFINAE를 사용하여 함수를 사용하고 있습니다. 그러나 나는 그것에 대한 변수를 사용하고 싶습니다,하지만 SFINAY varaiables (또는 내가 잘못) 일을 생각하지 않습니다. 여기

지금까지 내 (작업) 코드 :

//////////////////////////////////////////////////////////////////////////////// 

template < typename T ,typename I > 
inline 
typename std::enable_if< std::is_same< T ,char >::value ,int >::type 
str_printf (T* szBuff ,int iLen ,const T* szFrmt ,I iNum) 
{ return sprintf_s(szBuff ,iLen ,szFrmt ,iNum); } 

template < typename T ,typename I > 
inline 
typename std::enable_if< std::is_same< T ,wchar_t >::value ,int >::type 
str_printf (T* szBuff ,int iLen ,const T* szFrmt ,I iNum) 
{ return swprintf_s(szBuff ,iLen ,szFrmt ,iNum); } 

//////////////////////////////////////////////////////////////////////////////// 

template < typename T > 
inline 
typename std::enable_if< std::is_same< T ,char >::value ,const char* >::type 
Dflt_Frmt() { return "%i"; } 

template < typename T > 
inline 
typename std::enable_if< std::is_same< T ,wchar_t >::value ,const wchar_t* >::type 
Dflt_Frmt() { return L"%i"; } 

//////////////////////////////////////////////////////////////////////////////// 

template < typename T ,typename I > 
inline 
std::basic_string< T ,std::char_traits <T> > 
to_string (I iNum ,const T* pszFrmt) 
{ 
    const int iLen (65); 
    T szBuff [iLen] = {0}; 

    std::basic_string< T ,std::char_traits <T> > frmt ((pszFrmt && (*pszFrmt)) ? pszFrmt : Dflt_Frmt<T>()); 
    str_printf(szBuff ,iLen ,frmt.c_str() ,iNum); 

    return szBuff; 
} 

//////////////////////////////////////////////////////////////////////////////// 

이이 나는

//////////////////////////////////////////////////////////////////////////////// 

template < typename T ,typename I > 
inline 
std::basic_string< T ,std::char_traits <T> > 
to_string (I iNum ,const T* pszFrmt) 
{ 
    const int iLen (65); 
    T szBuff [iLen] = {0}; 

    // declare a Variable of const T* and initialie it with "%i" or L"%i" 
    typename std::enable_if< std::is_same< T ,char >::value  ,const char* >::type  dft("%i"); 
    typename std::enable_if< std::is_same< T ,wchar_t >::value ,const wchar_t* >::type  dft (L"%i"); 
    // doesn't work (error : type is not a member of std::enable_if<...> ! 

    std::basic_string< T ,std::char_traits <T> > frmt ((pszFrmt && (*pszFrmt)) ? pszFrmt : dft); 

    str_printf(szBuff ,iLen ,frmt.c_str() ,iNum); 

    return szBuff; 
} 

//////////////////////////////////////////////////////////////////////////////// 

은 내가 simillar 방식으로이 작업을 수행 할 수 있습니다 (분명히이 일하는 아니에요) 할 싶은 것이 또는 작업 버전이 가장 좋은 방법입니까? 또는이 작업을 수행하는 방법>

문자열 스트림을 사용하기 위해 제안 할 필요가 없습니다 (이 질문에 대한 내용은 아닙니다).

MSVS 2010 사용 (부스트 없음).

감사합니다.

+0

더 나은 사양으로 시작하면, 몇 가지 예제 코드와 원하는 출력 (단위 테스트 스타일에서 좋을 것입니다). 이렇게하면 이러한 모든 템플릿의 요점을 이해하는 것이 훨씬 쉬워 져서 당신이 여기 저기에 쏟아져 나오는 전화를 부추길 수 있습니다. –

답변

2

솔직히, 이것은 내가 생각할 수있는 유일한 솔루션입니다 : 그것은 꽤 아니다

template <typename T> struct Dft { static const T* value; }; 
template <> const char* Dft<char>::value = "%i"; 
template <> const wchar_t* Dft<wchar_t>::value = L"%i"; 

template < typename T ,typename I > 
inline 
std::basic_string< T ,std::char_traits <T> > 
to_string (I iNum ,const T* pszFrmt) 
{ 
    const int iLen (65); 
    T szBuff [iLen] = {0}; 

    std::basic_string< T ,std::char_traits <T> > frmt ((pszFrmt && (*pszFrmt)) ? pszFrmt : Dft<T>::value); 

    str_printf(szBuff ,iLen ,frmt.c_str() ,iNum); 

    return szBuff; 
}; 

,하지만 작동합니다.

+0

나는 내 생각보다 훨씬 더 설명력이 뛰어나다. 감사. –

1

두 번째 코드 블록에서 enable_if을 사용하면 서식 파일의 서명에서 사용하지 않기 때문에 하드 오류가 발생합니다. 변수 dft의 유형을 계산하려면 boost::mpl::if_과 같은 것이 필요할 수 있습니다. 두 가지 경우 모두 작동하도록 형식을 얻으려면 좁은 문자열에서 넓은 문자열로 변환 할 수 있다고 생각합니다.

+0

@Jeremiah Willcock : 귀하의 repons 주셔서 감사합니다. 캐스트 제안에 감사드립니다. 서명 논증에 대해 자세히 설명해 주시겠습니까? 나는 그게 무슨 뜻인지 완전히 이해하지 못합니다. –

+0

'enable_if'를 사용하여 특정 과부하 또는 특수화가 템플릿 인수에 따라 선택되는지 여부를 제어 할 수 있지만 함수 나 클래스의 본문을 인스턴스화 할 때까지 컴파일러는 이미 사용할 오버로드를 이미 알고 있습니다 . 따라서'enable_if'가 거기에서 실패하면, 컴파일러는 에러를 출력합니다; 근본적으로 "너무 늦어서"그 템플릿을 사용하지 못하게됩니다. –

+0

@Jeremiah Willcock : 네, 저는 그 말을 사과했습니다. –

0

IMO, 당신이 여기서하려는 것은 꽤 희망없는 노력입니다. "% i"변환은 부동 소수점 유형이 아닌 정수에서만 작동하므로 코드는 Iint 인 경우에만 작동합니다. 다른 유형의 경우 사용자 은 코드가 정의 된 동작을 수행하기 위해 (올바른) 형식 문자열을에 전달해야합니다. 잠시 동안이 문제를 무시하고 Iint이 아닌 경우 사용자가 (올바른) 형식 문자열을 전달한다고 가정합니다.

앞으로 몇 가지 다른 항목으로 확장 할 수도 있지만 실제로는 형식 문자열 유형의 경우 두 가지 가능성이 있습니다 : char * 또는 wchar_t *.일을 처리하는 올바른 방법은 간단한 과부하처럼 (또는 전문성 당신이 주장하는 경우) 그되는 경우, 보인다

template <class T> 
std::string to_string(T val, char *fmt = "%i") { 
    // for the moment using `sprintf`, simply because every knows it -- not really 
    // advising its use in production code. 
    char buffer[256]; 
    sprintf(buffer, fmt, val); 
    return std::string(buffer); 
} 

template <class T> 
std::wstring to_string(T val, wchar_t *fmt = L"%i") { 
    wchar_t buffer[256]; 
    wsprintf(buffer, fmt, val); 
    return std::wstring(buffer); 
} 

을 지금, 당신은 본질적으로 무언가를 "유형에 스위치"를하고있는 C++에서는 거의 항상 피할 수 있습니다 (일반적으로 가장 잘 피할 수 있습니다). 실행 시간 대신 컴파일 타임에 수행 중이거나 어쨌든 시도하려는 사소한 세부 사항은 실제로 변경되지 않습니다.

1 음, (당신은 Iunsigned int이고 값이 int로 표현 될 수있는 범위 내에있는 경우 작동한다고 주장 할 수도 있습니다,하지만 당신이 희망을 수있는 최선 관하여 심지어 매우 의심 스럽습니다).

+0

그런데 단일 매개 변수로 호출하면 이러한 오버로드가 모호합니다. 물론 앞에서 말했듯이 두 가지 유형 모두에 대해 to_string 함수 템플리트를 올바르게 구형 화하는 것이 효과적입니다. –

+0

@Mikael : 죄송합니다. 나는 조금 너무 게으른 ... –

+0

답장을 보내 주셔서 감사합니다. 그러나 여기서 문제는 to_string (...)을 구현해야하는 방식이 아니라는 것입니다. 그것은 템플릿 프로그래밍의 연습입니다. –

관련 문제