2014-09-23 7 views
4

나는, 매우 간단하게 몇 가지 코드가 다소 다음과 같습니다 Y::Faa 수동 Y::operator<<를 지정하는 데 대한 모호한 연산자를 피할 수있는 방법이모호한 연산자 << 선택

#include <iostream> 
#include <type_traits> 

namespace X { 
    struct Foo {int x;}; 
    struct Bar {int x;}; 

    template <typename T , typename = typename std::enable_if< 
                   std::is_same<decltype(T::x),int>::value 
                  >::type> 
    std::ostream & operator<<(std::ostream & os, const T&) { 
     return os; 
    } 
} 

namespace Y { 
    struct Faa : X::Foo {int y;}; 
    struct Baz {int x; int y;}; 

    template <typename T , typename = typename std::enable_if< 
                   std::is_same<decltype(T::x),int>::value && 
                   std::is_same<decltype(T::y),int>::value 
                  >::type> 
    std::ostream & operator<<(std::ostream & os, const T&) { 
     return os; 
    } 
} 


int main() { 
    // Everything is ok 
    X::Foo x; 
    std::cout << x; 

    Y::Baz k; 
    std::cout << k; 

    // Problems.. 
    Y::Faa y; 

    // std::cout << y; // <--operator is ambiguous 
    Y::operator<<(std::cout, y); 

    return 0; 
} 

있습니까? 그렇지 않다면, 왜?

+0

대한 제한은 매우 약한 것 같다 (너무 많은 유형이 허용됩니다). 예를 들어 수정할 수 있습니까? 유형 특성을 사용하여? – dyp

+0

실제 코드에서는 다양한 멤버 메서드의 존재를 확인하는 실제 특성을 만들었지 만 그 아이디어는 같습니다. 나는 이것이 아직 여기의 문제라고 생각하지 않는다. – Svalorzen

+0

필자는 허용 된 유형의 목록과 같은 것을 생각했습니다. 네임 스페이스의 직접 멤버로 의도 된 유형을 "결정"할 수있는 항목. 그런 다음 'x'라는 멤버가있는 멤버를 선택할 수 있습니다. – dyp

답변

3

인수의 조건에 공백이 아닌 공백이 있으므로 (실제로는 1st가 2nd를 대체) 두 함수가 충돌합니다. 함수 오버로딩은 서명이 다른 경우에만 작동합니다. 그래서, 우리는이 옵션이이 문제를 해결하기 위해 :

변경 조건 그래서 그들은 빈 교차점을 가지고

template<typename T> 
struct sfinae_has_member_y { 
    static int has(...); 
    template<typename U = T, typename = decltype(U::y)> 
    static char has(const U& value); 
    enum { value = sizeof(char) == sizeof(has(std::declval<T>())) }; 
}; 

또는 다른 C를 사용 (수동 1 enable_if&& !sfinae_has_member_y<T>::value 조건을 추가하여 y 필드를 가진 금) ++ 구조체/클래스 템플릿 특수화과 같이 겹치는 인수를 지원하는 기능입니다. 당신이 intbool를 교체 할 경우, 다른 분야도 추가 할 수 있습니다 enable_if``를 통해 부과

template<typename T, bool> 
struct Outputter { 
}; 
template<typename T> 
struct Outputter<T, false> { 
    static std::ostream & output(std::ostream & os, const T&) { 
     os << "x"; 
     return os; 
    } 
}; 
template<typename T> 
struct Outputter<T, true> { 
    static std::ostream & output(std::ostream & os, const T&) { 
     os << "y"; 
     return os; 
    } 
}; 

template<typename T, typename = std::enable_if_t<std::is_same<decltype(T::x), int>::value>> 
std::ostream & operator<<(std::ostream & os, const T& a) { 
    return Outputter<T, sfinae_has_member_y<T>::value>::output(os, a); 
}