2017-12-20 1 views
1

다음 코드는 MSVC 2017 년까지 거부 (그러나 GCC/연타에 의해 허용)된다과부하 해결 : 사용자 정의 변환보다 const/ref를 조정하고 있습니까?

class BA 
{ 
private: 
    operator int() const; 
}; 

template <typename A, typename B> 
class Builder {}; 

template <typename C> 
struct Concatenable; 

template <int N> struct Concatenable<char[N]> 
{ 
    using type = char[N]; 
}; 

template <int N> struct Concatenable<const char [N]> 
{ 
    using type = const char[N]; 
}; 

template <> struct Concatenable<BA> 
{ 
    using type = char *; 
}; 

template<typename A, typename B> 
Builder<typename Concatenable<A>::type, typename Concatenable<B>::type> 
operator+(const A &, const B &) 
{ 
    return {}; 
} 

int main() 
{ 
    BA ba; 
    char array[] = {'a', 'b'}; 
    ba + array; 
} 

오류 : MSVC가 const char (&)[2]BA보다 더 나은 char[2]을 조정하는 것을 고려하고있다처럼 보이는

example.cpp 
40 : <source>(40): error C2666: 'operator +': 2 overloads have similar conversions 
31 : <source>(31): note: could be 'Builder<char *,char [2]> operator +<BA,char[2]>(const A &,const B (&))' 
     with 
     [ 
      A=BA, 
      B=char [2] 
     ] 
40 : <source>(40): note: or  'built-in C++ operator+(__int64, char [2])' 
40 : <source>(40): note: while trying to match the argument list '(BA, char [2])' 
40 : <source>(40): note: note: qualification adjustment (const/volatile) may be causing the ambiguity 

int로 변환합니다. 표준을 읽으면서 이것이 사실이 아니어야합니다.

[over.ics.rank]는 표준 변환 시퀀스가 ​​항상 사용자 정의 변환 시퀀스보다 우수한 변환이라고 말합니다. 지금 : 템플릿에서 인스턴스화

  • operator+ 두 표준 변환 시퀀스
  • 사용 내장 한 사용자 정의 전환 서열 및 표준 변환 시퀀스 (ptrdiff_t, char * 이상)

따라서 [over.match.best]의 규칙에 따르면, 내 operator+은 항상 다른 것보다 나쁘지 않으며, 어떤 주장을하는 것이 좋습니다. 따라서 선호해야합니다. BA에서 operator int 제거 또는 유사 const char[] 상기 배열의 변화, 또는 비 CONST 걸릴 operator+ 번째 매개 변수를 변경하는 것은 B& MSVC 행복하게

참고있다.

내가 무엇을보고 있지 않습니까?

+0

다르게 마킹'운영자 int' (암시 적 사용자 정의 변환 연산자도 허용하는 이유?). 이것은 VC++의 버그 인 것 같습니다. 또한 참조를 바인딩으로 변환하는 것으로 간주됩니까? – VTT

+0

적어도 내 독서에서 "신원 전환"으로 간주됩니다 ... http://eel.is/c++draft/over.ics.ref#1 – peppe

답변

1

암시 적 변환 시퀀스는 인수별로 비교됩니다. 한 가지 논쟁의 ICS와 다른 논증의 ICS를 비교하지 마십시오. 첫 번째 인수에 대한 ICS는 두 번째 argumnet에 대해 더 나은 ICS를 가진 오버로드를 결정할 때 관련이 없습니다.

오버로드 X는 인수 중 하나보다 Y가 나쁘지 않고 적어도 하나 이상의 인수에서 더 우수하면 Y를 오버로드하는 것보다 낫습니다 (다양한 후기 단계 tiebreakers 무시). 하나의 과부하가 하나의 인수에 대해서는 ICS가 더 좋지만 다른 인수에 대해서는 ICS가 더 나쁘면 둘 다 다른 인수보다 우수합니다.

슬랙 채팅에서 논의했듯이 MSVC는 두 참조 바인딩을 비교할 때만 적용 할 수있는 ICS-comparison tiebreaker을 잘못 적용하고 있습니다. 이렇게하면 내장 함수가 두 번째 인수에서 더 나은 ICS를가집니다. 이것은 tiebroken 표준 변환 순서는 중요하지 않습니다. 그것은 여전히 ​​더 좋습니다.

추가 예 : 'explicit`는 잘 작동해야로서

void f(int, ...);  // #1 
void f(double, char); // #2 
f(10, 'c'); // ambiguous: #1 is better for the first argument 
      //   #2 is better for the second argument 

struct C { operator int() const; }; 
void g(C, int);  // #1 
void g(int, double); // #2 
g(C(), 1.0); // ambiguous: #1 is better for the first argument 
      //   #2 is better for the second argument 
+0

'하나의 과부하가 하나의 인수에 대해 더 나은 ICS를 가졌지 만 또 다른 논쟁에 대한 ICS가 나 빠지면 다른 ICS보다 나을 것이 없다. 그러나 모든 과부하에 대해 하나의 과부하가 ICS보다 우수하다. 순위를 잘못 읽었습니까? – peppe

+0

@peppe 참조 바인딩 규칙을 가진 MSVC의 세계에서, 내장형의'char [2]'는'operator +'의'const char (&) [2]'보다 나은 ICS입니다. –

관련 문제