3

따라서 다음 코드는 clang ++ (3.8.0)에서 성공적으로 빌드 및 실행되지만 g ++ (6.3. 0) 및 vC++ (19.10.24903.0). g ++ 및 vC++ 모두 연산자 & &의 재정의에 대해 불평합니다.clang ++, g ++, vC++ (C++ 14 모드)에서 C++ friend 함수 템플릿 오버플로 및 SFINAE 다른 동작

누구에게 어떤 컴파일러가 잘못되었는지 알 수 있습니까? 코드 컴파일에 실패한 컴파일러의 경우 컴파일 오류에 대한 해결 방법은 무엇입니까?

#include <functional> 
#include <iostream> 

template <typename T> 
struct awaitable 
{ 
    friend awaitable<void> operator&&(awaitable a1, awaitable a2) 
    { 
     std::cout << "operator&&(awaitable a1, awaitable a2) - T: " << typeid(T).name() << std::endl; 
     return awaitable<void>{}; 
    } 

    template <typename U = T, typename std::enable_if<!std::is_same<U, void>::value>::type* = nullptr> 
    friend awaitable<void> operator&&(awaitable<void> a1, awaitable<U> a2) 
    { 
     std::cout << "operator&&(awaitable<void> a1, awaitable<U> a2) - U: " << typeid(T).name() << std::endl; 
     return awaitable<void>{}; 
    } 

    template <typename U = T, typename std::enable_if<!std::is_same<U, void>::value>::type* = nullptr> 
    friend awaitable<void> operator&&(awaitable<U> a1, awaitable<void> a2) 
    { 
     std::cout << "operator&&(awaitable<U> a1, awaitable<void> a2) - U: " << typeid(T).name() << std::endl; 
     return awaitable<void>{}; 
    } 
}; 

int main(int argc, const char * argv[]) 
{ 
    awaitable<int> a1, a2, a3, a4; 
    auto ar = a1 && (a1 && a2) && (a2 && a3) && a4; 
} 

그 소리 ++ : http://coliru.stacked-crooked.com/a/cb01926bbcacdfb0

g ++ : http://coliru.stacked-crooked.com/a/73d17a5ae26f22eb

VC++ : http://webcompiler.cloudapp.net/

답변

3

SFINAE하지 템플릿의 개별 구성원의 수준에서, struct awaitable<T>에서 즉, 템플릿 인스턴스화 수준에서 작동합니다. awaitable<void>은 유효한 인스턴스 생성이며 클래스의 모든 3 멤버의 선언을 인스턴스화하여 후자를 복제합니다.

두 정의가 서로 충돌하지 않습니다. 즉 각 정의가 자신과 충돌합니다 example) (more details).

해결 방법 1

밖으로의 클래스 (당신이 한 것과 부여 정확히 동일하지 - 이러한 것 친구 템플릿의 예) 도우미 운영자 정의

#include <functional> 
#include <iostream> 

template <typename T> 
struct awaitable 
{ 
    friend awaitable<void> operator&&(awaitable a1, awaitable a2) 
    { 
     std::cout << "operator&&(awaitable a1, awaitable a2) - T: " << typeid(T).name() << std::endl; 
     return {}; 
    } 

    template<typename U> 
    friend std::enable_if_t<!std::is_void<U>::value, awaitable<void>> operator&&(awaitable<void> a1, awaitable<U> a2); 

    template<typename U> 
    friend std::enable_if_t<!std::is_void<U>::value, awaitable<void>> operator&&(awaitable<U> a1, awaitable<void> a2); 

}; 

template<typename U> 
std::enable_if_t<!std::is_void<U>::value, awaitable<void>> operator&&(awaitable<void> a1, awaitable<U> a2) 
{ 
    std::cout << "operator&&(awaitable<void> a1, awaitable<U> a2) - U: " << typeid(U).name() << std::endl; 
    return {}; 
} 

template<typename U> 
std::enable_if_t<!std::is_void<U>::value, awaitable<void>> operator&&(awaitable<U> a1, awaitable<void> a2) 
{ 
    std::cout << "operator&&(awaitable<U> a1, awaitable<void> a2) - U: " << typeid(U).name() << std::endl; 
    return {}; 
} 

int main(int argc, const char * argv[]) 
{ 
    awaitable<int> a1, a2, a3, a4; 
    auto ar = a1 && (a1 && a2) && (a2 && a3) && a4; 
} 

해결 방법 2

사용없이 SFINAE 전혀하지만의 전문화3210. 특수화가 취소되었음을 유의하십시오. 기본 구현은 awaitable<void>의 특수한 경우이며 특수화는 다른 모든 경우입니다.

#include <functional> 
#include <iostream> 

template <typename T, bool isvoid = std::is_void<T>::value> 
struct awaitable 
{ 
    friend awaitable<void> operator&&(awaitable a1, awaitable a2) 
    { 
     std::cout << "operator&&(awaitable a1, awaitable a2) - void" << std::endl; 
     return {}; 
    } 
}; 

template <typename T> 
struct awaitable<T, false> 
{ 
    friend awaitable<void> operator&&(awaitable a1, awaitable a2) 
    { 
     std::cout << "operator&&(awaitable a1, awaitable a2) - T: " << typeid(T).name() << std::endl; 
     return {}; 
    } 

    friend awaitable<void> operator&&(awaitable<void> a1, awaitable<T> a2) 
    { 
     std::cout << "operator&&(awaitable<void> a1, awaitable<T> a2) - U: " << typeid(T).name() << std::endl; 
     return {}; 
    } 

    friend awaitable<void> operator&&(awaitable<T> a1, awaitable<void> a2) 
    { 
     std::cout << "operator&&(awaitable<T> a1, awaitable<void> a2) - void" << std::endl; 
     return {}; 
    } 
}; 

int main(int argc, const char * argv[]) 
{ 
    awaitable<int> a1, a2, a3, a4; 
    auto ar = a1 && (a1 && a2) && (a2 && a3) && a4; 
} 
+0

니스는 g ++ 및 vC++ 모두의 컴파일 오류를 해결합니다! 그러나 행동 현명한, clang ++ 올바르게 또는 g ++/vC++ 동작 했습니까? – Dejavu

+0

몇 가지 추가 정보가 추가되었습니다. – rustyx

+0

그래서 당신은 clang이 충돌하는 정의를 방지하지 않음으로써 결함이 있음을 의미합니까? 또는 clang은 충돌하는 정의가 * 정확히 * 동일하면 어떻게 든 "병합"할 수있었습니다. – Dejavu