2011-02-17 4 views
3

을 감안할 때 :초기화 프로그램이있는 정적 const 멤버에 사용할 수있는 정의가 없습니다?

template<class T> 
struct S { 
    static int const N = 1; 
}; 

extern template class S<int>; 

template<class T> 
int f(T n) { 
    return n + S<T>::N; // line 10 
} 

int main() { 
    return f(1);  // line 14 
} 

//template class S<int>; // intentionally commented out to trigger error 

내가 얻을 :

foo.cpp: In function ‘int f(T) [with T = int]’: 
foo.cpp:10: instantiated from ‘const int S<int>::N’ 
foo.cpp:10: instantiated from ‘int f(T) [with T = int]’ 
foo.cpp:14: instantiated from here 
foo.cpp:10: error: explicit instantiation of ‘S<int>::N’ but no definition available 

그러나 가 왜 오류를받을 수 있나요? 정의가 다른 할 수 있도록

  1. 명시 적 템플릿 인스턴스화 선언을하는 요점은, 아직 컴파일러 (안 링커) 오류를 제공합니다. (실제 응용 프로그램에서는 현재 주석 처리 된 인스턴스화 선언이 어쨌든 다른 번역 단위에 있습니다.)
  2. 이 경우 값은 상수 이니셜 라이저이므로 컴파일러는 이론상 단순히 값을 직접 사용할 수 있습니다.
  3. 명시 적 템플릿 인스턴스화 선언을 수행하지 않을 때 나는 (기묘하게) S<T>::N을 명시 적으로 정의 할 필요가 없습니다.

Mac OS X 10.6.6의 g ++ 4.2.1입니다.

+0

'static const' 대신'enum {N = 1};을 사용할 수 있습니다. – kennytm

+0

@KennyTM : 그 질문에 대답하지 않습니다. 분명히,이 예제는 실제 코드의 예제입니다. 실제 코드는 ~ 0으로 설정된 부호없는 long을 필요로하며, AFAIK, enum은 "unsigned"일 수 없습니다. –

+1

이건 그냥 컴파일러 버그라고 생각합니다. m ++에서 g ++ 4.4.0으로 잘 컴파일됩니다. – TonyK

답변

2
extern template class S<int>; 

가 나는 명시 적 인스턴스화 곳 S<int>를 찾는 컴파일러를 알려줍니다으로이 행, 오류를 발생시키는 생각하지만, 명시 적 인스턴스가 존재하지 않습니다. 따라서 오류.

이 줄을 주석 처리하면 코드가 잘 컴파일되어야한다고 생각합니다.


편집 :

음,이 참조 : 내가 말했듯이 http://www.ideone.com/oQnOi

, 그것은 잘 컴파일합니다!


편집 :

내가 $ 9.4.2/4 $ 14.5.1.3로, 클래스 템플릿의 정적 멤버에 적용되지 않습니다 (마크 B에 의해 인용) [온도를 생각합니다. 정적 부재를 강제하지 않는다] 정적 공간 범위에서 정의된다 :

는 공간 범위에 제공 될 수있는 정적 데이터 부재의 정의 정적 회원의 클래스 템플릿의 정의를 묶습니다.

는 예, 그것은 "를 제공해야합니다"라고하지 않습니다이 아니라 "제공 될 수있다"

template<class T> class X { static T s; }; 
template<class T> T X<T>::s = 0; 

, 같은주의 사항을 따른다.그래서 네임 스페이스 범위에서 클래스 템플릿의 정적 멤버의 정의는 선택 사항이라고 생각합니다. 9.4.2/2 내지

+0

하나는 해석 할 수도 있습니다 "제공되지 않을 수도 있습니다 *"*의 반대의 의미로 "제공 될 수 있습니다", "반대편이 제공되지 않을 수 있습니다 *"다른 곳에서는 허용 될 표준이 있습니까? –

+1

@ Oli : "* 전혀 제공되지 않을 수도 있습니다 *"라고 해석합니다. 즉, 네임 스페이스 범위의 정의는 선택 사항입니다. – Nawaz

2

:

그 클래스 정의 정적 데이터 부재의 선언되지 정의하고 cvqualified 보이드 이외 불완전한 형태가 될 수도있다. 정적 데이터 구성원에 대한 정의는 구성원 클래스 정의를 포함하는 범위의 네임 스페이스에 나타납니다. 의 정의에서 네임 스페이스 범위 인 정적 데이터 멤버의 이름은 연산자를 사용하여 클래스 이름으로 으로 규정되어야합니다.

그리고 9.4.2/4에서 :

정적 데이터 부재 CONST 일체형 또는 CONST 열거 타입 인 경우 클래스 정의 선언은하여야 constantinitializer 지정할 수 정수 상수 표현 (5.19)이어야합니다. 이 경우 멤버는 범위가 인 정수 상수 표현에 나타날 수 있습니다. 프로그램에 이 사용되고 이름 공간 범위 정의에 이니셜 라이저가 포함되어 있지 않은 경우 멤버는 네임 스페이스 범위에 정의 된대로 여전히 이어야합니다.

9.4.2/4에서 이러한 정의가 정의되지 않은 경우 프로그램이 올바른 형식이 아니라는 것을 추론 할 수 있습니다 ("... 여전히 정의해야합니다 ...").

관련 문제