어떤 것을 "ODR 사용"한다는 것은 무엇을 의미합니까?


93

이것은 또 다른 질문 의 맥락에서 나온 것입니다 .

분명히 클래스 템플릿의 멤버 함수는 ODR을 사용하는 경우에만 인스턴스화됩니다. 누군가 그게 정확히 무슨 뜻인지 설명해 주시겠습니까? ODR (One Definition Rule)에 대한 위키피디아 기사 에는 " ODR 사용 "이 언급되어 있지 않습니다 .

그러나 표준은 그것을 다음과 같이 정의합니다.

이름이 잠재적으로 평가 된 표현식으로 나타나는 변수 는 상수 표현식 (5.19)에 나타나기위한 요구 사항을 충족하는 객체가 아닌 한 odr 사용 되며 lvalue-to-rvalue 변환 (4.1)이 즉시 적용됩니다.

[basic.def.odr]에 있습니다.

편집 : 분명히 이것은 잘못된 부분이며 전체 단락에는 여러 가지에 대한 여러 정의가 포함되어 있습니다. 이것은 클래스 템플릿 멤버 함수와 관련된 것일 수 있습니다.

잠재적으로 평가 된 식에서 참조 될 때 오버로드 확인에 의해 선택된 경우 이름이 잠재적으로 평가 된 식 또는 후보 함수 집합의 멤버로 나타나는 오버로드되지 않은 함수는 순수 가상이 아닌 경우 odr 사용됩니다. 함수 및 이름이 명시 적으로 규정되지 않았습니다.

그러나이 규칙이 여러 컴파일 단위에서 어떻게 작동하는지 이해하지 못합니다. 클래스 템플릿을 명시 적으로 인스턴스화하면 모든 멤버 함수가 인스턴스화됩니까?


2
[basic.def.odr] / 6은 클래스 템플릿의 멤버 함수에 적용됩니다. "하나 이상의 정의가있을 수 있습니다. [...]"
dyp

3
"클래스 템플릿을 명시 적으로 인스턴스화하면 모든 멤버 함수가 인스턴스화됩니까?" 예, [temp.explicit] / 8 + 9 참조
dyp

답변:


72

이는 단지 선언이 아닌 엔티티에 대한 정의를 제공해야하는시기를 지정하기 위해 표준에서 사용하는 임의의 정의 일뿐입니다. 표준은 단지 "중고"라고 말하는 것이 아닙니다. 왜냐하면 이것은 문맥에 따라 다양하게 해석 될 수 있기 때문입니다. 그리고 일부 ODR 사용은 일반적으로 "사용"과 연관되는 것과 실제로 일치하지 않습니다. 예를 들어, 가상 함수는 실제로 프로그램의 어느 곳에서도 호출되지 않더라도 순수하지 않는 한 항상 ODR을 사용합니다.

전체 정의는 §3.2 , 두 번째 단락에 있지만 여기에는 정의를 완료하기위한 다른 섹션에 대한 참조가 포함되어 있습니다.

템플릿과 관련하여 ODR 사용은 문제의 일부일뿐입니다. 다른 부분은 인스턴스화입니다. 특히 §14.7에서는 템플릿이 인스턴스화되는시기를 다룹니다. 그러나 두 가지는 관련되어 있습니다. §14.7.1 (암시 적 인스턴스화)의 텍스트는 상당히 길지만 기본 원칙은 템플릿이 사용되는 경우에만 인스턴스화되며이 컨텍스트에서 사용됨은 ODR 사용을 의미합니다. 따라서 클래스 템플릿의 멤버 함수는 호출되거나 가상이고 클래스 자체가 인스턴스화되는 경우에만 인스턴스화됩니다. 표준 자체는 여러 곳 에서이를 고려합니다. 개별 요소에 대한 std::list<>::sort사용 <이지만을 <호출 하지 않는 한을 지원하지 않는 요소 유형에 대해 목록을 인스턴스화 할 수 있습니다 sort.


ODR 사용이 "구체화 된 임시"와 겹칠 수 있습니까?
v.oddou

23

간단히 말해서 odr-used는 정의가 있어야하는 상황에서 무언가 (변수 또는 함수)가 사용됨을 의미합니다.

예 :

struct F {
   static const int g_x = 2;
};

int g_x_plus_1 = F::g_x + 1; // in this context, only the value of g_x is needed.
                             // so it's OK without the definition of g_x

vector<int>  vi;
vi.push_back( F::g_x );      // Error, this is odr-used, push_back(const int & t) expect
                             // a const lvalue, so it's definition must be present

위의 push_back은 MSVC 2013에서 전달되었습니다.이 동작은 표준 준수가 아니며 gcc 4.8.2 및 clang 3.8.0 모두 실패했습니다. 오류 메시지는 다음과 같습니다.`K :: g_x '에 대한 정의되지 않은 참조


vi.push_back( F::g_x );C ++에서 와 같이 정적 데이터 멤버를 odr- 사용할 수 있습니까?
Rankaba

그러나 rvalue를 전달할 수도 있습니다 const int&. 정적 const 멤버를 rvalue로 간주 할 수 있습니까?
scottxiao

8
간결한 시작 문장의 +1 : "일반적인 단어에서 odr-used는 정의가 있어야하는 상황에서 무언가 (변수 또는 기능)가 사용됨을 의미합니다."
Paul Masri-Stone

1
나는 당신이 그 코드를 어떻게 컴파일하는지 이해하지 못한다. 그들은 같은 TU에 있습니까?. 그렇다면 F :: g_x는 이전에 이미 정의되어 push_back있습니다. 물론 통과합니다. 그렇지 않습니까?
Lewis Chan

1
@bigxiao " rvalue도 전달할 수 있습니다. "Yes 및 임시 개체는 컴파일러와 해당 개체에 바인딩 된 참조에 의해 생성됩니다. lvalue를 전달할 때 OTOH는 lvalue의 평가에서 참조하는 해당 객체를 전달 함을 의미합니다. lvalue를 전달하면 함수의 매개 변수가 올바른 객체를 참조 할 것으로 예상 할 수 있습니다. 컴파일러는 임시를 생성하지 않습니다. 임시를 원한다면 operator+.
curiousguy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.