8
내가 가진

최소한의 예는 약간 복잡입니다 Kid 문제에 대해 Parent 일치 약 :이 클래스의 범위에 기능을 constexpr하는 포인터를 전달 부모 템플릿의 매개 변수를 추론 할 학대

prog.cc:7:15: note: candidate template ignored: could not match 'Parent' against 'Kid' 
constexpr int operator*(A, Parent<N>*) { return N; } 

우리가 코드를 조금 변경하면 더 황당한으로 활용하려면 다음

struct A { }; 

template <int> 
struct Parent { }; 

template <int N> 
constexpr int operator*(A, Parent<N>*) { return N; } 

template <class T> 
using ptr = T*; 

template <int> 
struct Other { }; 

template <int N> 
struct Kid: Parent<N> { 
    static constexpr int s = A{} * ptr<Kid>{}; 
}; 

int main() { 
    Other<Kid<2>::s>{}; 
} 

[clang]도 코드를 컴파일합니다. 그래서 ... 벌레일까요? 아니면 제 정신이 나기 시작 했나요?

+2

100 % 답변을 도울 수는 없지만, 일반적으로'gcc'는'clang'보다 더 관대하다는 것을 발견했습니다. 반면에 후자는 표준을 좀더 가깝게 따르고 있습니다. 나는 그것이 여기의 경우라고 생각할 것이다. 그러나 인텔 컴파일러는 코드도 허용합니다. – davmac

답변

6

법은 법의 서한에 적합합니다. 예, KidParent에서 파생되었습니다. 그러나이 관계는 Kid이 완전히 정의 된 유형일 때만 설정할 수 있습니다. 잘, [class.mem]/6 :

클래스가 완전히 정의 된 객체 타입 클래스 지정자의 폐쇄시 ([basic.types]) (또는 완전한 형태)} 간주

. 클래스 멤버 지정 내에서 클래스는 함수 본문, 기본 인수, noexcept 지정자 및 기본 중첩 클래스의 해당 항목을 포함하여 완료로 간주됩니다. 그렇지 않으면 자체 클래스 구성원 사양 내에서 불완전한 것으로 간주됩니다.

우리는 "강조된"부분에 있습니다. 우리가 포인터를 다룰지라도, 클래스는 아직 포인터 변환이 유효하다고 정의 된 것으로 간주되지 않습니다. GCC는 지나치게 관대합니다.

+1

네, 그 대답은 **처럼 들리네 ** :) 그리고 적어도 당신은 내가 미쳤다고 말하지 않았다;) 그런데 - 멋진 겨울 모자! –

+0

아무도 이의를 제기하지 않으면 버그를 제기 할 것입니다 ... 짧은 MCVE를 찾으러 가자.;) –

+1

@ W.F. 나는 누군가가 이것에 대해 더 많은 것을 밝힐 수 있는지를보기를 희망한다. 그리고 단어의 어떤 스트레칭으로 당신은 정신 나간 것이 아니라, 그 예를 들어 ...;) – StoryTeller