2014-09-27 3 views
8

I가 다음과 같은 C++ 11 코드 (간체 버전) :정적 constexpr 클래스 멤버가 클래스 외부 정의가 필요한 경우는 언제입니까?

struct Info 
{ 
    const char * name; 
    int version; 
}; 

class Base 
{ 
public: 
    const Info info; 
    Base (Info info) : info (info) {} 
}; 

class Derived : public Base 
{ 
public: 
    static constexpr Info info = {"Foobar", 2}; 
    Derived() : Base (info) {} 
}; 

int main() 
{ 
    static Derived derived; 
    return 0; 
} 

GCC 4.9.1 컴파일 및 링크이 코드 벌금을. 반면에 Clang 3.5.0은 정의되지 않은 참조에 대해 불평합니다 :

/tmp/test-109c5c.o: In function `main': 
test.cc:(.text+0x1c): undefined reference to `Derived::info' 
test.cc:(.text+0x22): undefined reference to `Derived::info' 
clang: error: linker command failed with exit code 1 (use -v to see invocation) 

맞습니까? 이 코드가 합법적인가 아닌가? static constexpr 멤버 (대부분 this question)에 관한 규칙에 대한 나의 이해는 변수의 주소가 사용될 때만 클래스 밖의 정의가 필요하다는 것입니다. 하지만 Derived :: info의 주소를 사용하지 않거나 어디에서나 참조를 사용합니다. Base 생성자에만 값을 전달합니다. 내가 찾은

다양한 해결 방법 :

  • 모두 생성자 (자료 및 파생) constexpr를 확인합니다. 이것은 예제의 것보다 더 복잡한 실제 클래스의 옵션 일 수도 있고 아닐 수도 있습니다. 어쨌든 그것을 시도 할 것입니다.
  • main에서 파생 된 인스턴스를 정적 ​​기간이 아닌 자동 기간으로 선언하십시오. 이는 실제 프로젝트에 대한 옵션이 아닙니다. Derived 클래스는 플러그인 구현이며, 인스턴스를 공유 객체의 공용 심볼로 내 보내야합니다.
  • Derived :: info를 완전히 제거하고 중괄호로 초기화 된 임시 객체 (예 : Base ({"Foobar", 2}))로 Base 생성자를 호출합니다. 이 솔루션을 사용할 수는 있지만 더 많은 멤버가 struct Info에 추가되므로 추한 것입니다 (제 의견으로는).
+1

[vector :: push_back odr - 정적 클래스 멤버에 대한 정의되지 않은 참조를 일으키는 값을 사용할 수 있습니다.] (http://stackoverflow.com/questions/272900/undefined-reference-to-static-class-member) –

+0

데이터 멤버 대신 멤버 함수로 만들면 어떻습니까? – imreal

+0

@ πάνταῥεῖ 나는 std :: vector를 사용하지 않고있다. 그러나 당신의 링크는 나를 올바른 길로 인도한다. 감사! –

답변

2

아하, 문제는 암시적인 Info(const Info &) 복사 생성자 인 것으로 보입니다. 해당 생성자에 const Info & 참조를 전달하려면 Derived :: info 주소를 가져와야합니다.

분명히 GCC는 복사 생성자를 최적화 할 때 Clang보다 더 공격적입니다. -fno-elide-constructors을 사용하면 GCC는 Derived :: info에 대한 정의되지 않은 참조에 대해 불평합니다.

어떤 경우에는 Base 및 Derived 생성자를 constexpr로 선언하면 Base :: info를 별도의 Derived :: info에서 복사하지 않고 초기화 할 수 있습니다. 실행 시간.

관련 문제