C ++의 클래스 선언 내에서 const 멤버 초기화


80

PHP 및 C #에서 상수는 선언 된대로 초기화 할 수 있습니다.

class Calendar3
{
    const int value1 = 12;
    const double value2 = 0.001;
}

두 수학 벡터를 비교하기 위해 다른 클래스와 함께 사용되는 펑터에 대한 다음 C ++ 선언이 있습니다.

struct equal_vec
{
    bool operator() (const Vector3D& a, const Vector3D& b) const
    {
        Vector3D dist = b - a;
        return ( dist.length2() <= tolerance );
    }

    static const float tolerance = 0.001;
};

이 코드는 g ++에서 문제없이 컴파일되었습니다. 이제 C ++ 0x 모드 (-std = c ++ 0x)에서 g ++ 컴파일러는 오류 메시지를 출력합니다.

오류 : 정수가 아닌 유형의 정적 데이터 멤버 'tolerance'의 클래스 내 초기화에 'constexpr'이 필요합니다.

static const클래스 정의 외부 에서이 멤버를 정의하고 초기화 할 수 있다는 것을 알고 있습니다 . 또한 비 정적 상수 데이터 멤버는 생성자의 이니셜 라이저 목록에서 초기화 할 수 있습니다.

그러나 PHP 또는 C #에서 가능한 것처럼 클래스 선언 내에서 상수를 초기화하는 방법이 있습니까?

최신 정보

staticg ++의 클래스 선언 내에서 이러한 상수를 초기화 할 수 있기 때문에 키워드를 사용 했습니다. 선언 여부에 관계없이 클래스 선언에서 상수를 초기화하는 방법이 필요합니다 static.


5
I used static keyword just because it was possible to initialize such constants within the class declaration in g++. I just need a way to initialize a constant in a class declaration no matter if it declared as static or not.회원이되어야할지 말지 결정 하는 잘못된 방법 static입니다. 어휘 게으름이 코드의 의미를 결정하게하지 마십시오.
궤도에서 가벼운 경주

That's the wrong way to decide whether a member should be static or not.동의하지 않습니다. 정회원에게는 상관 없다고 생각합니다.
ezpresso

3
@expresso : 전혀 요. static인스턴스 별 정보로 상수 가 아닌 멤버를 초기화 할 수 있습니다 . 상수가 특정 인스턴스가 아닌 유형의 속성이라고 결정한 것이 static바로 타이핑 단축키를 좋아했기 때문이 아니라 이를 만드는 이유 입니다.
궤도에서 가벼운 경주

@lightless : 글쎄, 가능하지만 다른 값을 가진 동일한 인스턴스 특정 상수의 초기화를 사용하는 이유를 알 수 없습니다. 나는 그것을 위해 비 상수 클래스 필드를 사용했습니다!
ezpresso

4
개체 인스턴스화 후 변경되지 않는 이유는 무엇입니까? 될 있는 struct myType { const std::time_t instantiated; myType() : instantiated(std::time(0)) {} };모든 것이 되어야 합니다 . 회원 과 비회원 모두에게 적용됩니다 . const conststaticstatic
궤도에서 가벼운 경주

답변:


136

C ++ 11에서 static데이터가 아닌 멤버, static constexpr데이터 멤버, static const정수 또는 열거 형 데이터 멤버는 클래스 선언에서 초기화 될 수 있습니다. 예 :

struct X {
    int i=5;
    const float f=3.12f;
    static const int j=42;
    static constexpr float g=9.5f;
};

이 경우 i모든 클래스 인스턴스의 멤버 는 컴파일러 생성 생성자 X5의해 초기화되고 f멤버는로 초기화됩니다 3.12. static const데이터 부재 j를 초기화 42하고, static constexpr데이터 부재 g로 초기화된다 9.5.

이후 floatdouble통합 또는 열거 유형이 아닌, 같은 회원이어야합니다 constexpr, 또는 비 static허용 할 클래스 정의의 초기화의 순서이다.

C ++ 11 이전에는 static const정수 또는 열거 유형의 데이터 멤버 만 클래스 정의에 이니셜 라이저를 가질 수있었습니다.


이것이 사양이 된 표준 부분에 대한 링크가 있습니까? 나는 방금 그것을 사용하기 시작했고 (C ++ 14로 컴파일하지만) 컴파일러가 나를 위해 이것을함으로써 많은 시간을 절약하기 위해 서서 작동한다는 것에 기뻐합니다. 그러나 귀하의 답변을 읽을 때까지 나는 그것이 작동 해야하는지 확실하지 않았습니다 ! 공식적인 말이 내 자신감에 도움이 될 것입니다, 하하. Fwiw 저도 회원들과 함께 일하고 char const n[3]{'a', 'b', 'c'};있습니다.
underscore_d

왜 그런지 궁금 static const int하지만 static constexpr float? 무슨 뜻 float and double are not of integral or enumeration type이야?
mrgloom

@mrgloom : 예, float 및 double은 아닙니다. 데이터 유형이 정수로 변환 될 수 있다면 정수 유형입니다.
ppadhy

45

const int 유형 이외의 정적 멤버 변수를 초기화하는 것은 C ++ 11 이전의 표준 C ++가 아닙니다. gcc 컴파일러는 -pedantic옵션 을 지정하지 않는 한 이에 대해 경고하지 않고 유용한 코드를 생성합니다 . 그러면 다음과 유사한 오류가 발생합니다.

const.cpp:3:36: error: floating-point literal cannot appear in a constant-expression
const.cpp:3:36: warning: ISO C++ forbids initialization of member constant ‘tolerance’ of non-integral type ‘const float’ [-pedantic]

그 이유는 C ++ 표준이 부동 소수점 구현 방법을 지정하지 않고 프로세서에 맡기기 때문입니다. 이 문제와 기타 제한 사항을 해결하기 위해 constexpr도입되었습니다.


14

예. constexpr오류가 말한대로 키워드를 추가하십시오 .


1
아마도 그는 그의 프로젝트에 C ++ 11이 필요하지 않을까요?
Marc Mutz-mmutz 2012 년

6
그가 언급 한 문제는 그가 C ++ 11로 컴파일을 시도했기 때문에 소개되었습니다. 즉, 그는 C ++ 11을 지원하고자합니다. :)
Unknown1987

1

하나의 메서드에서만 필요한 경우 로컬에서 정적으로 선언 할 수 있습니다.

struct equal_vec
{
    bool operator() (const Vector3D& a, const Vector3D& b) const
    {
        static const float tolerance = 0.001f;
        Vector3D dist = b - a;
        return ( dist.length2() <= tolerance );
    }
};

1

다른 버전의 g ++ (GNU C ++ 컴파일러)로 컴파일하려면 동일한 코드가 필요하기 때문에이 문제가 실제로 발생했습니다. 그래서 매크로를 사용하여 어떤 버전의 컴파일러가 사용되고 있는지 확인한 다음 그에 따라 조치를 취해야했습니다.

#if __GNUC__ > 5
 #define GNU_CONST_STATIC_FLOAT_DECLARATION constexpr
#else
 #define GNU_CONST_STATIC_FLOAT_DECLARATION const
#endif

GNU_CONST_STATIC_FLOAT_DECLARATION static double yugeNum=5.0;

이것은 g ++ 버전 6.0.0 이전의 모든 것에 'const'를 사용하고 g ++ 버전 6.0.0 이상에는 'constexpr'을 사용합니다. 솔직히 g ++ 버전 6.2.1까지이 사실을 알아 차리지 못했기 때문에 변경이 발생하는 버전에 대한 추측 입니다. 제대로하려면 g ++의 부 버전과 패치 번호를 확인해야 할 수도 있습니다.

https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html

사용 가능한 매크로에 대한 자세한 내용은

gnu를 사용하면 모든 곳에서 'const'를 사용하고 -fpermissive플래그 로 컴파일 할 수 있지만 경고가 표시되고 내 항목이 깔끔하게 컴파일되는 것이 좋습니다.

그것은 gnu 컴파일러에 한정되어 있기 때문에 좋지는 않지만 다른 컴파일러와 비슷하게 할 수 있다고 생각합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.