developer tip

std :: is_struct 유형 특성이없는 이유는 무엇입니까?

copycodes 2020. 12. 26. 15:38
반응형

std :: is_struct 유형 특성이없는 이유는 무엇입니까?


유형 T이 클래스 인지 확인하기 위해 사용할 수있는 것을 보았습니다 .

bool isClass = std::is_class<T>::value;

클래스와 구조체 모두에 대해 true를 반환합니다. 나는 C ++에서 그것들이 거의 똑같다는 것을 알고 있지만, 유형 특성에서 그들 사이에 차이가없는 이유를 알고 싶습니다. 이 차이를 확인하는 것이 항상 쓸모가 있습니까? 아니면 이해하지 못하는 이유가 더 있습니까?


클래스와 구조체 모두에 대해 true를 반환합니다. 나는 C ++에서 그것들이 거의 똑같다는 것을 알고 있지만, 유형 특성에서 그들 사이에 차이가없는 이유를 알고 싶습니다.

불행히도 이것은 C ++에서 일반적인 오해입니다. 때로는 근본적인 오해에서 비롯되지만 때로는 영어의 모호함에서 비롯됩니다. 부정확 한 컴파일러 진단, 잘못 쓰여진 책, 잘못된 SO 답변에서 비롯 될 수 있습니다.

아마도 다음과 같이 읽었을 것입니다.

"멤버와베이스의 기본 가시성을 제외하고는 구조체와 클래스간에 C ++에 차이가 없습니다."

이 구절은 오해의 소지가있는 의미로 해석 될 수 있습니다 . "차이 없음"과 같은 구절을 사용할 때 정체성평등 의 개념 을 구별하기 어렵 기 때문 입니다.

사실 C ++에는 1985 년 이후로 구조체가 없었습니다. 클래스 만 있습니다.

키워드 class키워드로 선언하는 유형 struct클래스 입니다. 기간. 키워드 struct및 해당 키워드를 사용하여 클래스를 정의 할 때 기본값 인 가시성 규칙은 C…와의 하위 호환성을 위해서만 유지되었지만 구문 문제입니다. 결과 유형이 실제로 다른 종류가되는 것은 아닙니다.

유형 특성은 문자 그대로 만들 것이 없기 때문에 구별하지 않습니다.


다음과 같은 빈 정의에 대한 의미 체계의 차이를 구별하는 것은 불가능합니다.

class C {
public:

};

...에서

struct S {

};

또는 유사하게

class C {

};

struct S {
private:

};

structvs class키워드를 제외하고는 감지 할 수있는 행동 차이가 없습니다. 이 Q & A를 참조하십시오 .

참고 : @KyleStrand에서 언급했듯이 파생에는 명시 적 액세스 지정자도 필요하므로 S : private Base {};and C : Base {};는 동일합니다. S : Base {};and C : public Base {};, 여기서 S구조체 C는 클래스이고 Base둘 중 하나 수 있습니다.


그들은 같은 것입니다. 유일한 차이점 (기본 멤버 가시성)은 컴파일 타임에만 존재합니다. 그렇지 않으면 struct사이에 전혀 차이가 없습니다 class.

ETA : 아마도 당신이 원하는 것은 std::is_pod당신의 클래스가 "평범한 오래된 데이터 유형"인지 알려줄 것입니다. 이 질문에 대한 많은 토론과 논평은 이것이 구별이 있어야한다고 생각하는 사람들이 실제로 원하는 것임을 나타내는 것처럼 보입니다.


다른 사람들은 C ++에서 키워드 structclass멤버 가시성의 차이를 제외하고는 동일한 의미를 가지고 있다고 올바르게 지적했습니다 .

이렇게 정의 된 집계 유형을 "구조", "클래스"또는 "weiruewzewiruz"라고 부르는 것은 사용자에게 달려 있습니다. 의사 소통을 위해 일반적으로 확립 된 규칙을 따르는 것이 좋습니다. 그래서 "weiruewzewiruz"를 사용하지 않는 것이 좋습니다.

또한 단어 선택에 대한 지침으로 의미 적 차이를 사용하는 것이 좋습니다. struct내부 논리와 불변성이 많지 않은 단순한 집계 데이터 의 경우를 사용하는 것이 더 일반적입니다. 일반적인 용도는 struct point { float x; float y; };. 이러한 유형은 종종 문헌에서 "구조체"또는 "구조물"이라고합니다. fprintfC ++에서 사용하는 누군가 가 첫 번째 인수를 "FILE 구조체에 대한 포인터"라고 언급하는 것은 놀라운 일이 아닙니다 . FILE은 "More Effective C ++", Item 34에서 Scott Meyers가 의미하는 바의 예입니다.

두 언어 [C 및 C ++ -pas]로 컴파일되는 구조 정의가 두 컴파일러에 의해 동일한 방식으로 배치된다고 가정하는 것이 안전합니다.

자연어와 관련하여 "구조"라는 단어 선택은 우연이 아닙니다. Meyers는 비트 수준까지 두 언어에서 동일한 의미를 갖는 평범한 오래된 데이터 집합체에 대해 이야기하고 있습니다.

프로그래밍 언어와 관련하여 문제가되는 데이터 집합의 C ++ 정의가 키워드 struct또는 class(공용 액세스 지정자 사용)을 사용하는지 여부는 중요하지 않습니다 . struct집계의 C ++ 의미 체계가 C 구조체의 의미 체계이기 때문에 아마도 더 자연스러운 선택 일 것입니다. 또한를 사용 struct하면 C 및 C ++ 소스 모두 하나의 유형 정의를 더 쉽게 공유 할 수 있습니다.

C ++ 표준은 상호 운용성의 경우뿐만 아니라 자연어와 프로그래밍 언어 모두에서 "struct"및 "structure"를 사용합니다. 1.7 / 5 : "A structure declaration as"또는 3.2 / 4 struct X; // declare X as a struct type. 가장 흥미로운 것은 9/8로 interop-criteria의 기반을 마련하는 것입니다.

8 표준 레이아웃 구조체는 클래스 키 구조체 또는 클래스 키 클래스로 정의 된 표준 레이아웃 클래스입니다. [...]

이것을 읽는 사람이 C ++에 구조체가 없다고 주장 할 수있는 방법은 저를 넘어선 것입니다. "구조체"와 "클래스"라는 용어가 서로 관련하여 명시 적으로 설정되어 있기 때문에 이것은 분명히 편집 오류가 아닙니다.


그러나 단어 선택과 맛의 문제보다 더 흥미로운 것은 명백하고 검증 가능한 차이입니다. C ++ 집계는 어떤 상황에서 C와 호환되고 호환 struct됩니까? 아마도이 질문이 귀하의 질문의 기초가 되었습니까? 견적서에 언급 된 표준 레이아웃이 기준입니다. 9/7에 자세히 설명되어 있으며 기본적으로

  • 상속 계층 구조의 한 클래스에만 비 정적 데이터 멤버 정의가있을 수 있습니다 (아마도 표준이 계층 구조의 다른 수준에서 정의 된 데이터 요소의 순서를 지정하지 않기 때문일 수 있습니다).
  • 가상 기능 또는 가상 기본 클래스는 허용되지 않습니다 (런타임 정보에 필요한 추가 인스턴스 데이터로 인해).
  • 모든 구성원은 동일한 "액세스 제어"(공개, 보호 또는 개인, 아마도 액세스 제어에 의해 구현을 주문할 수 있기 때문에)를 갖습니다.

표준은 다음과 같이 말합니다.

9 [참고 : 표준 레이아웃 클래스는 다른 프로그래밍 언어로 작성된 코드와 통신하는 데 유용합니다. 레이아웃은 9.2에 지정되어 있습니다 .—end note]

물론 C로 컴파일되는 구조체 정의는 이러한 기준을 충족하므로 Scott Meyers의 주장입니다. FILEfrom stdio.h는 눈에 띄는, 아주 사소한 예입니다. 객체 레이아웃은 구현에 따라 다르며 컴파일러 옵션으로 만 변경 될 수 있기 때문에 표준은 보장하지 않습니다.

클래스에 표준 레이아웃이 있는지 여부는 유형 trait으로 테스트 할 수 있습니다 std::is_standard_layout<T>. cppreference의 예제에서 영감을 얻은 다음 프로그램 은 표준에 배치 된 주요 사례를 확인합니다.

#include <cstdio>
#include <typeinfo>
#include <type_traits>

using namespace std;

struct funcOnlyT // fine
{
    int f();
};

class podT {   // "class" is ok
    int m1;
    int m2;
};

struct badAccessCtrlT { // bad: public/private
    int m1;
private:
    int m2;
};

struct polymorphicT {  // bad: polymorphic
    int m1;
    int m2;
    virtual void foo();
};


struct inheritOkT: podT // ok: inheritance, data only on one level
{
    int f();
};


struct inheritPlusDataT: podT // bad: inheritance, data on 2 levels
{
    int m3;
};

template<typename T1, typename T2>
struct templT     // ok with std layout types T1, T2
{
    T1 m1;
    T2 m2;
};

// print type "name" and whether it's std layout
template<typename T>
void printIsStdLayout()
{
    printf("%-20s: %s\n", 
            typeid(T).name(),
            std::is_standard_layout<T>::value 
                ? "is std layout" 
                : "is NOT std layout");
}

int main()
{
    printIsStdLayout<funcOnlyT>();
    printIsStdLayout<podT>();
    printIsStdLayout<badAccessCtrlT>();
    printIsStdLayout<polymorphicT>();
    printIsStdLayout<inheritOkT>();
    printIsStdLayout<inheritPlusDataT>();
    printIsStdLayout<templT<int, float> >();
    printIsStdLayout<FILE>();
}

샘플 세션 :

$ g++ -std=c++11 -Wall -o isstdlayout isstdlayout.cpp && ./isstdlayout
9funcOnlyT          : is std layout
4podT               : is std layout
14badAccessCtrlT    : is NOT std layout
12polymorphicT      : is NOT std layout
10inheritOkT        : is std layout
16inheritPlusDataT  : is NOT std layout
6templTIifE         : is std layout
9__sFILE64          : is std layout

C ++ 11 §9 / 8 ([클래스] / 8) :

" 표준 레이아웃 구조체 으로 정의 된 표준 레이아웃 클래스 클래스 키 struct 또는 클래스 키 class . 표준 레이아웃 조합은 으로 정의 된 표준 레이아웃 클래스 클래스 키 union .

C ++ 11 §9 / 10 ([클래스] / 10) :

A POD struct is a non-union class that is both a trivial class and a standard-layout class, and has no non-static data members of type non-POD struct, non-POD union (or array of such types). […]

Since a POD struct is a standard-layout class it is a subset of standard-layout struct. As far as I know this is the most general meaning of struct in the C++ standard. And so presumably what you're looking for is a type trait or set of type traits that lets you identify a standard-layout struct as such.

And voilà, looking at the list of type traits there's is_class and is_standard_layout. When a type satisifies ¹both it's a “struct”. Or more precisely, it's a standard-layout struct, as defined by C++11 §9/8.


Regarding

I'd like to know why there's not a distinction between [class and struct] in the type trait

Well, there is. That's the is_standard_layout trait.


Regarding

Is it always useless to check this difference, or is there some more reason that I don't understand?

No, it's not useless to check this difference. The standard defines standard-layout for the reason that it's very practically useful. As the standard itself notes,

C++11 §9/9 ([class]/9):

[Note: Standard-layout classes are useful for communicating with code written in other programming languages. Their layout is specified in 9.2.—end note ]


Notes:
¹ The is_class trait is true for a class or struct, but not for a union, even though the standard defines that “a union is a class”. I.e. the trait is more specific than the general terminology.

ReferenceURL : https://stackoverflow.com/questions/32719880/why-is-there-not-an-stdis-struct-type-trait

반응형