C почему структуры typedef уникальны по сравнению с примитивами typedef

#c

#c

Вопрос:

Почему a typedef для a struct считается уникальным типом, а a typedef для a std::string или другого примитива — нет? Подумайте, что у вас может быть два struct с одинаковыми компонентами, но они рассматриваются как два разных, не связанных типа.

Вот рабочий пример.

 #include <iostream>
//#define FAIL
#ifdef FAIL
// These are considered to be the same thing
typedef std::string StringEventA;
typedef std::string StringEventB;
#else
// But these are two entirely different types...
typedef struct {std::string str;} StringEventA;
typedef struct {std::string str;} StringEventB;
#endif

class Foo {
    public:
        void Handle(StringEventA event){std::cout<<"An";}
        void Handle(StringEventB event){std::cout<<"Bn";}
};

int main()
{
    StringEventA a;
    StringEventB b;
    Foo foo;
    foo.Handle(a);
    foo.Handle(b);
    
    return 0;
}
  

Комментарии:

1. То, что вы не называете структуры, не означает, что они одного типа (и если вы назвали их, вы не могли бы дать им одинаковое имя). Напротив, первый typedef разрешает тот же тип std::string .

2. Я не уверен, что понимаю, что вы имеете в виду, называя структуры. Также возможно ли достичь этих std::string определений типов тем же способом, что и структуры?

3. typedef struct StructA {std::string str;} StringEventA; . Если вы хотите, чтобы typedef считались разными, они должны разрешаться для разных типов.

4. Не так много связано с typedef . Первые два являются простыми псевдонимами типов, в то время как определения структур содержат свои собственные отличающиеся ype.

Ответ №1:

 struct {std::string str;} 
  

это определяет тип без имени.

 std::string 
  

это имя типа.

 typedef TYPE name;
  

это создает псевдоним name для типа TYPE .

В struct{} случае он предоставляет имя для неназванного типа, созданного в этой строке.

В std::string случае это псевдоним для уже названной вещи.

Итак, в одном случае вы создали 2 типа. typedef дал им только имена.

 template<class T, class Tag>
struct strong:T{
  using T::T;
};
  

это разумный хороший строгий typedef.

Далеко от совершенства, но достойно.

 struct tagA;
struct tagB;
using StringEventA=strong<std::string, tagA>;
using StringEventB=strong<std::stings, tagB>;
  

тег может содержать множество вещей, а не только структуры.

 template<class T, auto Tag>
struct strong:T{
  using T::T;
};
  

теперь тегом является любое значение времени компиляции.

 using StringEventA=strong<std::string, 'A'>;
using StringEventB=strong<std::stings, 'B'>;
  

например, char литерал.

Ваш компилятор может не поддерживать auto параметры шаблона. Проверьте.

Ответ №2:

Почему a typedef для структуры считается уникальным типом, а a typedef для std::string или другого примитива — нет?

typedef определяет псевдоним для типа. Он не определяет новый тип.

Строки

 typedef struct {std::string str;} StringEventA;
typedef struct {std::string str;} StringEventB;
  

эквивалентны

 struct AnonymousStruct1 {std::string str;};
typedef AnonymousStruct1 StringEventA;

struct AnonymousStruct2 {std::string str;};
typedef AnonymousStruct2  StringEventB;
  

Использование анонимных struct символов, которые используются для определения typdef , не являются одним и тем же типом, даже если они идентичны слово в слово.

Ответ №3:

В то время как другие ответы очень хорошо объясняют теорию, и на самом деле нет необходимости добавлять формулировки. Но иногда некоторые люди все еще хотят увидеть подтверждающий код для понимания. Итак, я написал небольшой код для g , который демонстрирует, что здесь происходит (онлайн-демонстрация):

 #include <iostream>
#include <typeinfo>
#include <cxxabi.h>

// Helper function for the raw char pointer gymnastics needed with __cxa_demangle
template<typename T> std::string get_typename() {
    char* type_name;
    int status;
    std::string resu<
    type_name = abi::__cxa_demangle(typeid(T).name(),0,0,amp;status);
    result = std::string(type_name);
    free(type_name);
    return resu<
}

// These are considered to be the same thing
typedef std::string StringEvent1;
typedef std::string StringEvent2;
// While these are considered to be different things
typedef struct {std::string str;} StringEvent3;
typedef struct {std::string str;} StringEvent4;

int main() {
    std::cout << "Name of StringEvent1: " << get_typename<StringEvent1>() << std::endl;
    std::cout << "Name of StringEvent2: " << get_typename<StringEvent2>() << std::endl;
    std::cout << "Name of StringEvent3: " << get_typename<StringEvent3>() << std::endl;
    std::cout << "Name of StringEvent4: " << get_typename<StringEvent4>() << std::endl;
}
  

Вывод:

 Name of StringEvent1: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
Name of StringEvent2: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
Name of StringEvent3: StringEvent3
Name of StringEvent4: StringEvent4
  

Таким образом, мы можем четко видеть, что и почему компилятор считает одинаковым или другим.

Приведенный выше код использует typeid() оператор для получения информации о (базовых) типах и специфичную для компилятора abi::__cxa_demangle() функцию для преобразования ее в формат, доступный для чтения человеком.

Ответ №4:

Не имеет значения, используете вы typeedef или нет; когда вы объявляете с struct ;

 struct A {};
struct B {};


typedef struct {std::string str;} StringEventA;
typedef struct {std::string str;} StringEventB;
  

в любом случае, это разные типы.

std::string уже определенный тип может содержать разные значения, но тип всегда один и тот же; просто у вас есть два псевдонима для std::string типа