2011-04-24 9 views
11

여러 가지 오버로드 된 글로벌 to_string() 함수를 사용하여 일부 유형 T을 가져 와서 문자열 표현으로 변환하려고합니다. 일반적인 경우, 나는 쓸 수 있도록하려면 :SFINAE를 사용하여 글로벌 연산자 <<를 확인하십시오.

template<typename T,class OutputStringType> inline 
typename enable_if<!std::is_pointer<T>::value 
       && has_insertion_operator<T>::value, 
        void>::type 
to_string(T const &t, OutputStringType *out) { 
    std::ostringstream o; 
    o << t; 
    *out = o.str(); 
} 

has_insertion_operator의 내 구현은 지금까지입니다 :

struct sfinae_base { 
    typedef char yes[1]; 
    typedef char no[2]; 
}; 

template<typename T> 
struct has_insertion_operator : sfinae_base { 
    template<typename U> static yes& test(U&); 
    template<typename U> static no& test(...); 

    static std::ostream &s; 
    static T const &t; 

    static bool const value = sizeof(test(s << t)) == sizeof(yes); // line 48 
}; 

(그것은 thisthis에서 차용.) 작동하는 것 같다 그 . 하지만 지금은 하지operator<<하지만 자신의 to_string()멤버 기능을 가지고 있습니까 유형, 즉 대한 to_string의 오버로드 버전을 갖고 싶어 :

template<class T,class OutputStringType> inline 
typename enable_if<!has_insertion_operator<T>::value 
       && has_to_string<T,std::string (T::*)() const>::value, 
        void>::type 
to_string(T const &t, OutputStringType *out) { 
    *out = t.to_string(); 
} 

has_to_string의 구현은 다음과 같습니다

#define DECL_HAS_MEM_FN(FN_NAME)          \ 
    template<typename T,typename S>          \ 
    struct has_##FN_NAME : sfinae_base {        \ 
    template<typename SignatureType,SignatureType> struct type_check; \ 
    template<class U> static yes& test(type_check<S,&U::FN_NAME>*); \ 
    template<class U> static no& test(...);       \ 
    static bool const value = sizeof(test<T>(0)) == sizeof(yes); \ 
    } 

DECL_HAS_MEM_FN(to_string); 

은 (이 부분은 잘 작동하는 것 같다. 그것은 this 각색입니다.) 그러나, 나는이있을 때 :

struct S { 
    string to_string() const { 
    return "42"; 
    } 
}; 

int main() { 
    string buf; 
    S s; 
    to_string(s, &buf); // line 104 
} 

내가 얻을 : SFINAE 안될 것 같다

foo.cpp: In instantiation of ‘const bool has_insertion_operator<S>::value’: 
foo.cpp:104: instantiated from here 
foo.cpp:48: error: no match for ‘operator<<’ in ‘has_insertion_operator<S>::s << has_insertion_operator<S>::t’ 

. has_insertion_operator을 올바르게 작성하여 operator<<을 사용할 수 있는지 여부를 결정합니다.

FYI : g ++ 4.2.1 (Mac OS X에서 Xcode의 일부로 제공됨)을 사용하고 있습니다. 또한 제 3 자 라이브러리 (예 : 부스트)가없는 표준 C++ 03 코드가 필요합니다.

감사합니다.

+1

확실히 모든 것이 가능하지만 * 왜 *? – Potatoswatter

+2

@Potatoswatter : 왜 중요하지 않습니다. 나머지 프로젝트에서는 제가하고있는 일을 알고 있다고 생각하십시오. 알고 있어야하는 경우 모든 유형의 매개 변수를 전달하여 지역화 된 오류 메시지의 일부를 구성하기위한 프레임 워크의 일부입니다.이 질문에 불필요한 모든 것에 대한 세부 사항. 그것을하는 방법을 아는 경우 질문에 대답하십시오. 대단히 감사하겠습니다. –

+2

항상 중요한 이유는 무엇입니까? – GManNickG

답변

10

나는 더 정확하게 this 대답에 충실해야했습니다. 실제로 동작하는 구현은 다음과 같습니다

namespace has_insertion_operator_impl { 
    typedef char no; 
    typedef char yes[2]; 

    struct any_t { 
    template<typename T> any_t(T const&); 
    }; 

    no operator<<(std::ostream const&, any_t const&); 

    yes& test(std::ostream&); 
    no test(no); 

    template<typename T> 
    struct has_insertion_operator { 
    static std::ostream &s; 
    static T const &t; 
    static bool const value = sizeof(test(s << t)) == sizeof(yes); 
    }; 
} 

template<typename T> 
struct has_insertion_operator : 
    has_insertion_operator_impl::has_insertion_operator<T> { 
}; 

나는 그것이 하지 실제로 SFINAE에 의존한다는 것을 믿는다.

+0

Wonderful : C++ 03 컴파일러에서 작동합니까? –

+0

시도해보고 알아보십시오. 어쨌든 –

+0

코드에 감사드립니다 :) –

1

라인 48의 value의 초기화 프로그램은 SFINAE가 작동하는 환경에 있지 않습니다. 표현식을 함수 선언으로 옮겨보십시오.

#include <iostream> 

struct sfinae_base { 
    typedef char yes[1]; 
    typedef char no[2]; 
}; 

template<typename T> 
struct has_insertion_operator : sfinae_base { 

    // this may quietly fail: 
    template<typename U> static yes& test(
     size_t (*n)[ sizeof(std::cout << * static_cast<U*>(0)) ]); 

    // "..." provides fallback in case above fails 
    template<typename U> static no& test(...); 

    static bool const value = sizeof(test<T>(NULL)) == sizeof(yes); 
}; 

그러나,이에 가고 세련의 양을 질문해야합니다. 서로 대립 할 직교가 아닌 메커니즘을 보았고 (to_stringoperator<<) 구현 된 코드가 그 점에서 괜찮은 것처럼 보였지만 가짜 가정이 주위에 던져지고있는 것을 들었습니다 (예를 들어 operator<<은 글로벌 대 멤버입니다).

+1

여러 가지 오류로 컴파일되지 않습니다. 첫 번째 오류는 'test'에 템플릿 매개 변수에 의존하는 인수가 없으므로 'test'선언을 사용할 수 있어야합니다. –

+0

BTW : 첫 번째 인수는 ostream이어야하므로 operator <<는 삽입 연산자 여야합니다. –

+0

BTW # 2 : ostream :: ostream()이 보호되어 있습니다. –

관련 문제