클래스 내부의 실제 정적 상수에 대한 enum 대 constexpr
내 의도를 말하면서 시작하겠습니다. 예전 (C ++) 시절에는 다음과 같은 코드가있었습니다.
class C
{
public:
enum {SOME_VALUE=27};
};
그런 다음 SOME_VALUE
코드 전체에서 컴파일 시간 상수로 사용할 수 있으며 컴파일러가 볼 수있는 곳에 C::SOME_VALUE
리터럴 27을 삽입합니다.
이제는 해당 코드를 다음과 같이 변경하는 것이 더 적합 해 보입니다.
class C
{
public:
static constexpr int SOME_VALUE=27;
};
이것은 훨씬 깨끗해 보이고 SOME_VALUE
잘 정의 된 유형을 제공 하며 C ++ 11에서 선호되는 접근 방식 인 것 같습니다. (적어도 나에게는 예상치 못한) 문제는 이것이 SOME_VALUE
외부 로 만들어야하는 시나리오를 유발 한다는 것입니다. 즉, 어떤 cpp 파일 어딘가에 다음을 추가해야합니다.
constexpr int C::SOME_VALUE; // Now C::SOME_VALUE has external linkage
이 문제를 일으키는 SOME_VALUE
경우는 C ++ 표준 라이브러리 코드에서 자주 발생하는 const 참조 가 사용될 때인 것 같습니다 (이 질문의 맨 아래에있는 예제 참조). 그런데 gcc 4.7.2를 컴파일러로 사용하고 있습니다.
이 딜레마로 인해 SOME_VALUE
일부 정적 constexpr 멤버 변수가 아닌 일부에 대한 정의를 cpp 파일에 추가하지 않으려면 열거 형 (예 : 구식)으로 다시 정의해야합니다. 컴파일러에게 이것이 컴파일 시간 상수 로만 처리되어야 하고 외부 링크가있는 객체가 아니라는 constexpr int SOME_VALUE=27
것을 의미 하는 방법이 없습니까? 그것과 함께 사용되는 const 참조가 보이면 임시를 만드십시오. 해당 주소가 사용 된 것을 확인하면 필요한 경우 컴파일 시간 오류를 생성합니다. 이는 컴파일 시간 상수이고 그 이상은 아니기 때문입니다.SOME_VALUE
다음은 SOME_VALUE
cpp 파일에 대한 정의를 추가해야하는 무해한 샘플 코드입니다 (다시 한 번 gcc 4.7.2로 테스트 됨).
#include <vector>
class C
{
public:
static constexpr int SOME_VALUE=5;
};
int main()
{
std::vector<int> iv;
iv.push_back(C::SOME_VALUE); // Will cause an undefined reference error
// at link time, because the compiler isn't smart
// enough to treat C::SOME_VALUE as the literal 5
// even though it's obvious at compile time
}
파일 범위의 코드에 다음 줄을 추가하면 오류가 해결됩니다.
constexpr int C::SOME_VALUE;
기록을 위해 static constexpr
버전은 C ++ 17에서 예상 한대로 작동합니다. N4618 부록 D.1 [depr.static_constexpr]에서 :
D.1
static constexpr
데이터 멤버의 재 선언 [depr.static_constexpr]이전 C ++ 국제 표준과의 호환성을 위해
constexpr
이니셜 라이저없이 정적 데이터 멤버를 클래스 외부에서 중복해서 다시 선언 할 수 있습니다. 이 사용법은 더 이상 사용되지 않습니다. [ 예 :
struct A {
static constexpr int n = 5; // definition (declaration in C++ 2014)
};
constexpr int A::n; // redundant declaration (definition in C++ 2014)
— 최종 예 ]
이를 허용하는 관련 표준 텍스트는 N4618 9.2.3 [class.static.data] / 3입니다 .
[...] 인라인 정적 데이터 멤버는 클래스 정의에서 정의 될 수 있으며 중괄호 또는 같음 이니셜 라이저를 지정할 수 있습니다 . 멤버가
constexpr
지정자 와 함께 선언 된 경우 이니셜 라이저없이 네임 스페이스 범위에서 다시 선언 될 수 있습니다 (이 사용은 더 이상 사용되지 않습니다. D.1 참조). [...]
이것은 constexpr
동일한 것, 인라인 정적 데이터 멤버 의 비 버전 을 도입 한 동일한 기계와 함께 제공됩니다 .
struct A {
static inline int n = 5; // definition (illegal in C++ 2014)
};
inline int A::n; // illegal
여기에는 세 가지 옵션이 있습니다.
클래스가 템플릿이면 헤더 자체에 정적 멤버의 정의를 넣으십시오. 컴파일러는 여러 번역 단위에서 하나의 정의로만 식별해야합니다 ([basic.def.odr] / 5 참조).
클래스가 템플릿이 아닌 경우 소스 파일에 쉽게 넣을 수 있습니다.
또는 constexpr 정적 멤버 함수 getSomeValue ()를 선언합니다.
class C { public: static constexpr int getSomeValue() { return 27; } };
I'd go with enum class:
http://en.cppreference.com/w/cpp/language/enum
http://www.stroustrup.com/C++11FAQ.html#enum
From the first link:
enum class Color { RED, GREEN=20, BLUE};
Color r = Color::BLUE;
switch(r) {
case Color::RED : std::cout << "red\n"; break;
case Color::GREEN : std::cout << "green\n"; break;
case Color::BLUE : std::cout << "blue\n"; break;
}
// int n = r; // error: no scoped enum to int conversion
int n = static_cast<int>(r); // OK, n = 21
Nowadays, the preferred way is:
enum class : int C { SOME_VALUE = 5 };
From the C++ standard N3797 S3.5/2-3
A name is said to have linkage when it might denote the same object, reference, function, type, template, namespace or value as a name introduced by a declaration in another scope:
— When a name has external linkage , the entity it denotes can be referred to by names from scopes of other translation units or from other scopes of the same translation unit.
— When a name has internal linkage , the entity it denotes can be referred to by names from other scopes in the same translation unit.
— When a name has no linkage , the entity it denotes cannot be referred to by names from other scopes.
A name having namespace scope (3.3.6) has internal linkage if it is the name of
— a variable, function or function template that is explicitly declared static; or,
— a non-volatile variable that is explicitly declared const or constexpr and neither explicitly declared extern nor previously declared to have external linkage; or
— a data member of an anonymous union.
My reading is that in the following code:
public:
static constexpr int SOME_VALUE=5;
constexpr int SOME_VALUE=5;
};
static constexpr int SOME_VALUE=5;
constexpr int SOME_VALUE=5;
All 4 instances of SOME_VALUE
have internal linkage. They should link with a reference to SOME_VALUE
in the same translation unit and not be visible elsewhere.
Obviously the first one is a declaration and not a definition. It needs a definition within the same translation unit. If GCC says so and MSVC does not, then MSVC is wrong.
For the purposes of replacing an enum, number 2 should work fine. It still has internal linkage without the static
keyword.
[Edited in response to comment]
you can do this
class C
{
public:
static const int SOME_VALUE=5;
};
int main()
{
std::vector<int> iv;
iv.push_back(C::SOME_VALUE);
}
This is not even C++11, just C++98
'UFO ET IT' 카테고리의 다른 글
NSData를 파일에 쓰는 가장 쉬운 방법 (0) | 2020.11.19 |
---|---|
log4j 두 번 로깅 (0) | 2020.11.19 |
해당하는 모나드 변환기 (IO 제외)가없는 모나드가 있습니까? (0) | 2020.11.18 |
소규모 .NET 오픈 소스 프로젝트를위한 지속적인 통합 (0) | 2020.11.18 |
Xcode 프로젝트 형식 : 3.1, 3.2, 6.3 및 8.0의 차이점은 무엇입니까? (0) | 2020.11.18 |