확인

2013-09-04 4 views
2

안녕하세요 다음과 같이 to_string 멤버 함수의 두 가지 구현을 작성하려는 : 그러나 나는를 사용하는 방법을 몰라, 내가 this을 보았다확인

template <typename T0> class foo 
{ 
public: std::string  to_string(); 
public: T0    m_Value; 
}; 

template <typename T0> std::string foo<T0>::to_string() 
{ 
std::stringstream ss; 
ss << m_Value; 
return ss.str(); 
} 

template <typename T0> std::string foo<T0>::to_string() 
{ 
return typeid(T0).name(); 
} 

코드, 나는 enable_if 및 mpl 향상에 전혀 익숙하지 않다. 두 번째 to_string 함수를 두 번째를 fallback으로 사용하려면 어떻게 정의해야합니까?

감사합니다.

+4

에서 boost::has_left_shift

//이 C++ (11)가 허용되어 사용할 수 있을까? – nijansen

답변

2
#include <iostream> 
#include <sstream> 
#include <typeinfo> 

// has_insertion_operator 
// ============================================================================ 

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> { 
}; 


// ToString 
// ============================================================================ 

namespace Detail { 
    template <typename T, bool> 
    struct ToString { 
     static std::string apply(const T& value) 
     { 
      std::stringstream s; 
      s << value; 
      return s.str(); 
     } 
    }; 

    template <typename T> 
    struct ToString<T, false> { 
     static std::string apply(const T& value) 
     { 
      return typeid(T).name(); 
     } 
    }; 
} 

template <typename T> 
inline std::string to_string(const T& value) 
{ 
    return Detail::ToString<T, has_insertion_operator<T>::value>::apply(value); 
} 

has_insertion_operator은 폴 J. 루카스에 의해 링크 된 답 (Using SFINAE to check for global operator<<?)에서 복사되었습니다.

(How to convert anything to string implicitly?)에 표시된 Mike Seymour의 인라인 친구 솔루션을 사용할 수도 있습니다. 나는 SFINAE를 선호한다.

3

내 걸릴 : 당신이 metafunction 걸릴 수 있습니다, 그것은 잘 작동합니다. 왜 그것이 작동하는지 잠시 논의 해 봅시다.

sizeof 실제로 표현식을 평가하지 않습니다. 그것의 타입을 추론하고 그 타입의 크기를 리턴한다. 유형 크기는 구현에 따라 정의되며 이에 대해서는별로 알 수 없지만 sizeof(char) != sizeof(char[2])을 알고 있으므로 테스트 할 때이 유형을 사용합니다.

우리는 any_t 유형을 사용하여 네임 스페이스 수준에서 스트림 연산자를 정의합니다.이 연산자는 모든 유형을 받아들이고 어떤 것을 반환하도록합니다 (ostream &이 아닌 한 실제로 어떤 유형이 중요하지는 않습니다). 이것은 유형에 스트림 연산자가 정의되어 있지 않은 경우 다시 폴백합니다. 클래스 자체에서 이제는 두 개의 함수를 정의합니다. 하나는 ostream &이며, 스트림 연산자가 정의 된 경우 결과이고, 하나는 대체 기능을 위해 정의한 반환 유형입니다.

sizeof(test(s << c)) 이제 다시 식을 평가하지 않고 반환 형식을 결정하고 크기 만 반환 할 수 있습니다.

이제 어떻게 작동하는지 알 수있는 모든 것이 남았습니다.이를 애플리케이션에 포함시키는 것입니다. 이를 수행하는 데는 여러 가지 방법이 있습니다. 당신은 아마 것이다 (C++ (11)가 당신을 위해 사용할 수있는 경우

template <bool, typename T> 
struct to_string_functor 
{ 
    std::string operator()(T const & t) const 
    { 
     std::stringstream ss; 
     ss << t; 
     return ss.str(); 
    } 
}; 

template <typename T> 
struct to_string_functor<false, T> 
{ 
    std::string operator()(T const &) const 
    { 
     return typeid(T).name(); 
    } 
}; 

template <typename T> 
struct foo 
{ 
    std::string to_string() const 
    { 
     return to_string_functor< 
      has_insertion_operator<T>::value, T 
     >()(m_Value); 
    } 
    /* ... */ 
}; 

는,이 작업을 수행하는 더 많은 방법, enable_if되는 또 하나 있습니다 또한 작동하는 한 가지 방법은, 이전의 C++ (11)는 펑터를 사용하는 것입니다 이를 위해 부분적으로 특수화 된 기능을 원한다.); 이 문제에 관해 this excellent blog post을 읽고 싶을 수도 있습니다.

그러나이 간단한 경우에는 필자가 내 의견을 반영해야합니다.

+1

+1 (링크 된 블로그는 확실히 추천입니다) – sehe

+0

고마워요. 나는 모든 것을 모을 수 있었다. – pisiiki

3

당신은 문서

#include <boost/type_traits/has_left_shift.hpp> 
#include <iostream> 

template <class T> 
struct contains { T data; }; 

template <class T> 
bool operator<<(const contains<T> &lhs, const contains<T> &rhs) { 
    return f(lhs.data, rhs.data); 
} 

class bad { }; 
class good { }; 
bool f(const good&, const good&) { } 

int main() { 
    std::cout<<std::boolalpha; 
    // works fine for contains<good> 
    std::cout<<boost::has_left_shift< contains<good> >::value<<'\n'; // true 
    contains<good> g; 
    g<<g; // ok 
    // does not work for contains<bad> 
    std::cout<<boost::has_left_shift< contains<bad> >::value<<'\n'; // true, should be false 
    contains<bad> b; 
    b<<b; // compile time error 
    return 0; 
}