4

Shape이라는 클래스가 있습니다.이 클래스는 모든 반복 가능 프로그램에서 초기화 할 수 있으며 Array이라는 클래스에는 단순히 Shape이 포함되어 있습니다. '모호성을 만들지 않고 std :: initializer_list 생성자를 사용 하시겠습니까?

prog.cxx:35:16: required from here 
prog.cxx:14:23: error: request for member ‘begin’ in ‘shape’, which is of non-class type ‘const int’ 
     : Shape(shape.begin(), shape.end()) {} 
       ~~~~~~^~~~~ 
prog.cxx:14:38: error: request for member ‘end’ in ‘shape’, which is of non-class type ‘const int’ 
     : Shape(shape.begin(), shape.end()) {} 
           ~~~~~~^~~ 

내가 돈 :

은 컴파일 오류가 Shape의 두 번째 생성자에 나타납니다
class Shape 
{ 
public: 
    template<typename Iterator> 
    Shape(Iterator first, Iterator last) 
     : m_shape(first, last) {} 

    template <typename Iterable> 
    Shape(const Iterable& shape) 
     : Shape(shape.begin(), shape.end()) {} 

    template<typename T> 
    Shape(std::initializer_list<T> shape) 
     : Shape(shape.begin(), shape.end()) {} 

private: 
    std::vector<std::size_t> m_shape; 
}; 

class Array 
{ 
public: 
    Array(const Shape& shape) 
     : m_shape(shape) {} 
private: 
    Shape m_shape; 
}; 

int main() { 
    Shape s{0};  // ok 
    Array a1({1, 2}); // ok 
    Array a2({0}); // error 
} 

: 그러나, 나는 내가 Array 초기화 할 때 내가 설명 할 수 컴파일 오류를 받고 있어요 여기서 무슨 일이 일어나고 있는지 이해해야합니다. initializer_list<T> 생성자 대신 Iterable 생성자가 호출되는 이유는 무엇입니까? {0}Array 생성자가있는 Shape 생성자의 차이점은 무엇입니까?

+0

재현 할 수 없습니다. 내 g ++ 6.3.0 및 내 clang ++ 3.8.1 함께 괜찮아요 ('s5' 줄에 오류 없음) 컴파일하십시오 (제 2 생성자에 대해'NDShape'를 수정하면 Shape에서 분명히 의미합니다.). 어떤 컴파일러를 사용하고 있습니까? – max66

+0

죄송합니다. 나는 코드를 너무 단순화했다.업데이트 된 코드는 이제 오류가 발생합니다. 감사! – AstrOne

+0

이제 오류가 있지만 신고 한 것과 완전히 다릅니다. "cbegin (const int &) [...]"호출에 대한 일치하는 함수가 없음을 확인할 수 있습니까? – max66

답변

3

코드가 잘못 작성되었지만 gcc가 주장하는 이유 때문이 아닙니다. 당신이 쓸 때 :

Array a2({0}); 

을 우리는 초기화 {0}를 사용 Array의 모든 생성자를 통해 오버로드 확인을한다.

옵션 # 1이다 : 우리는 시도로 재귀 것이다에

Array(Shape const&); 

때문에리스트를 초기화하는 동안 std::initializer_list의 특혜에 std::initializer_list<int> 생성자 템플릿을 호출 끝 {0}Shape 복사가 초기화.

그러나 단 하나의 옵션입니다. 옵션 # 2는 다음과 같습니다.

Array(Array&&); 

암시 적 이동 생성자. 이것이 후보인지 확인하기 위해 Array{0}으로 초기화 할 수 있는지 확인합니다. 기본적으로 다시 시작됩니다. 이 다음 단계에서는 을 0으로 초기화 할 수 있는지 확인합니다 (단 하나의 레이어가 제거되었으므로) 수 있습니다. - 이것이 모든 것을 허용하는 생성자 템플릿입니다. 여기에는 두 개의 사용자 정의 변환 시퀀스가 ​​포함되지만 that's ok for list-initialization이 포함됩니다.

  • 옵션 # 1 : {0} --> Shape
  • 옵션 # 2 :

    그래서 우리는 두 가지 옵션이 있습니다 0 --> Shape --> Array

어느 쪽도 다른 것보다 더 좋은, 그래서 호출이 모호합니다.


쉬운 수정 프로그램은 생성자 템플릿에 제약 조건을 실제로 추가하는 것입니다. 어쨌든 is_constructible_v<Shape, int>이 사실 이길 원하지 않기 때문에 일반적으로 좋은 연습입니다 ...

+0

+1. 흥미롭게도'explicit Array (const Shape &)'를 써서'Shape' ->'Array' 변환을 억제함으로써 옵션 2를 제거 할 수 있습니다. Clang-5.0.0 (행복한)과 GCC 7.2 (불평) [문제가 해결되면 동의하지 않음] (https://godbolt.org/g/6ty5e7). 버그 보고서를 제출하는 것이 합리적입니까? 상응하는 생성자를'explicit' [예상대로 작동] (https://godbolt.org/g/nEB2vo)로 선언함으로써 변환을 억제합니다 (제약 조건 추가보다 간단합니다). 그 단일 인수 생성자를 항상 '명시 적'후보로 간주해야한다고 추가 할 수 있습니다. – Julius

+0

@Julius 그래, 그게 gcc 버그라고 생각해. 그러나'explicit'은'Shape s (0); '과 같지 않으므로 충분하지 않습니다. 어쨌든 제약 조건이 필요합니다. – Barry