use - struct c++ code




Por que não há um traço do tipo std:: is_struct? (4)

Eu vi isso para verificar se um tipo T é uma classe que eu posso usar:

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

Ele retorna true para as classes e estruturas. Eu sei que em C ++ eles são quase a mesma coisa, mas eu gostaria de saber por que não há uma distinção entre eles no tipo de traço. É sempre inútil verificar essa diferença ou há mais alguma razão que eu não entendo?


Ele retorna true para as classes e estruturas. Eu sei que em C ++ eles são quase a mesma coisa, mas eu gostaria de saber por que não há uma distinção entre eles no tipo de traço.

Infelizmente este é um equívoco comum em C ++. Às vezes vem de mal-entendidos fundamentais, mas em outros momentos vem de uma ambiguidade em inglês. Pode vir de diagnósticos imprecisos do compilador, livros mal escritos, respostas SO incorretas…

Você provavelmente já leu algo assim:

"Não há diferença em C ++ entre uma estrutura e uma classe, exceto a visibilidade padrão de membros e bases."

Essa passagem pode ser interpretada em um sentido enganoso, porque as noções de identidade e igualdade são difíceis de distinguir quando se usam frases como "nenhuma diferença".

Na verdade, o C ++ não possui estruturas desde 1985. Ele possui apenas classes.

O tipo de tipos que você declara com a class keyword e a palavra-chave struct são classes . Período. A palavra-chave struct e as regras de visibilidade que são o padrão ao definir uma classe usando essa palavra-chave, foram mantidas apenas para compatibilidade com C… mas isso é uma coisa de sintaxe. Isso não faz com que os tipos resultantes sejam realmente de um tipo diferente.

O tipo de traço não faz distinção porque não há literalmente um para fazer.


C ++ 11 §9 / 8 ([classe] / 8) :

Uma estrutura de layout padrão é uma classe de layout padrão definida com a struct de chave de class ou a classe de chave de class . Uma união de layout padrão é uma classe de layout padrão definida com a union chave de classe .

C ++ 11 §9 / 10 ([classe] / 10) :

Uma estrutura POD é uma classe não-unida que é uma classe trivial e uma classe de layout padrão, e não possui membros de dados não estáticos do tipo struct não-POD, união não-POD (ou matriz de tais tipos). […]

Como uma estrutura POD é uma classe de layout padrão, ela é um subconjunto da estrutura de layout padrão . Tanto quanto eu sei, este é o significado mais geral de struct no padrão C ++. E assim, presumivelmente, o que você está procurando é um tipo de traço ou conjunto de características de tipo que permite identificar uma estrutura de layout padrão como tal.

E voilà, olhando para a lista de tipos de traços, há is_class e is_standard_layout . Quando um tipo satisfaz "é uma estrutura". Ou mais precisamente, é uma estrutura de layout padrão , conforme definido pelo C ++ 11 §9 / 8.

A respeito de

Eu gostaria de saber porque não há uma distinção entre [classe e estrutura] no tipo traço

Bem, existe. Esse é o traço is_standard_layout .

A respeito de

É sempre inútil verificar essa diferença ou há mais alguma razão que eu não entendo?

Não, não é inútil checar essa diferença. O padrão define layout padrão pelo motivo de ser muito prático. Como o próprio padrão observa,

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

[Nota: Classes de layout padrão são úteis para comunicação com código escrito em outras linguagens de programação. Seu layout é especificado em 9.2. — end note]

Notas:
is_class O traço is_class é verdadeiro para uma class ou struct , mas não para um union , mesmo que o padrão defina que “um sindicato é uma classe”. Ou seja, o traço é mais específico do que a terminologia geral.


Eles são a mesma coisa. A única diferença (visibilidade de membro padrão) existe somente em tempo de compilação. Não há diferença nenhuma entre struct e class .

ETA: O que você provavelmente quer é std::is_pod , que informará se sua classe é um "tipo de dados antigo". Grande parte da discussão e do comentário sobre essa questão parece indicar que é isso que aqueles que pensam que deveria haver uma distinção realmente querem.


Outros apontaram corretamente que, em C ++, as palavras-chave struct e class têm o mesmo significado, exceto pela diferença na visibilidade dos membros.

Se você chama tipos de agregados assim definidos, "structs" ou "classes" ou "weiruewzewiruz" é com você. No interesse da comunicação é geralmente aconselhável seguir as convenções estabelecidas, então eu aconselho contra "weiruewzewiruz".

Recomenda-se também usar diferenças semânticas como diretriz para escolhas de palavras. O uso de struct é mais comum para dados agregados simples que não possuem muita lógica interna e invariantes; um uso típico seria struct point { float x; float y; }; struct point { float x; float y; }; . Tais tipos são freqüentemente chamados de "estruturas" ou "estruturas" na literatura. Não seria surpreendente se alguém usando fprintf em C ++ se referisse ao primeiro argumento como um "ponteiro para uma estrutura FILE". FILE é um exemplo do que significa Scott Meyers em "C ++ Mais Eficaz", Item 34:

É seguro assumir que uma definição de estrutura que compila em ambas as linguagens [C e C ++ -pas] é apresentada da mesma maneira por ambos os compiladores.

No que diz respeito à linguagem natural, a palavra "estrutura" de escolha não é uma coincidência: Meyers está falando de um agregado de dados simples que possui semântica idêntica em ambas as linguagens, até o nível de bits.

Com relação à linguagem de programação, não importaria se a definição de C ++ do agregado de dados em questão usasse a palavra-chave struct ou class (com um especificador de acesso público). struct é talvez a escolha mais natural, porque a semântica de C ++ do agregado é a semântica de uma estrutura C. Além disso, o uso de struct permite que fontes C e C ++ compartilhem mais facilmente uma definição de tipo.

O padrão C ++ usa "struct" e "structure" na linguagem natural e de programação, não apenas em casos de interoperabilidade: 1.7 / 5: "Uma estrutura declarada como", ou 3.2 / 4 struct X; // declare X as a struct type struct X; // declare X as a struct type . O mais interessante é o 9/8, que serve de base para os critérios de interoperabilidade:

8 Uma estrutura de layout padrão é uma classe de layout padrão definida com a estrutura de chave de classe ou a classe de chave de classe. [...]

Como alguém lendo isso pode afirmar que não existem estruturas em C ++ está além de mim. Isso claramente não é um erro de edição porque os termos "struct" e "class" são explicitamente definidos em relação um ao outro.

Mais interessante do que escolhas de palavras e questões de gosto, no entanto, são diferenças manifestas e testáveis. Em que circunstâncias um agregado C ++ é comparável e compatível com uma struct C? Talvez esta questão estivesse subjacente à sua pergunta? O layout padrão mencionado na cotação é o critério. Ele é detalhado em 9/7 e essencialmente prescreve que

  • somente uma classe em uma hierarquia de herança pode ter definições de membros de dados não estáticos (provavelmente porque o padrão não deseja especificar a ordem dos elementos de dados definidos em níveis diferentes em tal hierarquia);
  • nenhuma função virtual ou classe base virtual é permitida (por causa dos dados de instância adicionais necessários para as informações de tempo de execução);
  • todos os membros têm o mesmo "controle de acesso" (público, protegido ou privado; provavelmente porque uma implementação é livre para ser solicitada pelo controle de acesso).

O padrão então diz

9 [Nota: Classes de layout padrão são úteis para comunicação com código escrito em outras linguagens de programação. Seu layout é especificado em 9.2. — end note]

É claro que uma definição de estrutura que compila em C preenche esses critérios, daí a afirmação de Scott Meyers. FILE de stdio.h é um exemplo proeminente e não muito trivial. Observe que o padrão não garante porque o layout do objeto depende da implementação e pode mudar apenas com uma opção do compilador.

Se uma classe tem layout padrão pode ser testada com o tipo de traço std::is_standard_layout<T> . O programa a seguir, inspirado em um exemplo de cppreference , verifica os principais casos estabelecidos no padrão.

#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>();
}

Sessão de amostra:

$ 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




typetraits