Действительно ли возможно получить символ* имя от шаблонного типа в C++

Вы пытались использовать «статическую» переменную счетчика. Статические переменные инициализируются только один раз и являются наилучшими кандидатами для использования в качестве переменных счетчика.

10
задан Rosco 27 February 2009 в 19:12
поделиться

7 ответов

Нет и это не будет работать надежное с идентификатором типа также. Это даст Вам некоторую внутреннюю строку, которая зависит от реализации компилятора. Что-то как "интервал", но также и "i" характерно для int.

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

template<typename A, typename B>
struct is_same { enum { value = false }; };

template<typename A>
struct is_same<A, A> { enum { value = true }; };

И затем сделайте

if(is_same<T, U>::value) { ... }

Повышение уже имеет такой шаблон, и следующий Стандарт C++ будет иметь std::is_same также.

Ручная регистрация типов

Можно специализироваться на типах как это:

template<typename> 
struct to_string {
    // optionally, add other information, like the size
    // of the string.
    static char const* value() { return "unknown"; }
};

#define DEF_TYPE(X) \
    template<> struct to_string<X> { \
        static char const* value() { return #X; } \
    }

DEF_TYPE(int); DEF_TYPE(bool); DEF_TYPE(char); ...

Так, можно использовать его как

char const *s = to_string<T>::value();

Конечно, можно также избавиться от основного шаблонного определения (и сохранить только предописание), если Вы хотите получить ошибку времени компиляции, если тип не известен. Я просто включал его здесь для завершения.

Я использовал статические элементы данных символьной константы* ранее, но они вызывают некоторые сложные проблемы, как вопросы, куда поместить объявления их и так далее. Специализации класса как вышеупомянутое решают проблему легко.

Автоматический, в зависимости от GCC

Другой подход должен полагаться на внутренности компилятора. В GCC следующее дает мне разумные результаты:

template<typename T>
std::string print_T() {
    return __PRETTY_FUNCTION__;
}

Возврат для std::string.

std::string print_T() [with T = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]

Некоторые substr волшебство, смешанное с find даст Вам строковое представление, которое Вы ищете.

13
ответ дан 3 December 2019 в 19:35
поделиться

Действительно легкое решение: Просто передайте строковый объект конструктору SomeClass, который заявляет, каков тип.

Пример:

#define TO_STRING(type) #type
SomeClass<int> s(TO_STRING(int));

Просто сохраните его и отобразите его в реализации GetClassName.

Немного более сложное решение, но все еще довольно легкий:

#define DEC_SOMECLASS(T, name) SomeClass<T> name;  name.sType = #T; 

template< typename T >
struct SomeClass
{
    const char* GetClassName() const { return sType.c_str(); }
    std::string sType;
};


int main(int argc, char **argv)
{
    DEC_SOMECLASS(int, s);
    const char *p = s.GetClassName();

    return 0;
}

Шаблон не вводит решение:

Вы могли также сделать свои собственные идентификаторы типов и иметь функцию для преобразования в и из идентификатора и строкового представления.

Затем можно передать идентификатор, когда Вы объявляете тип как шаблонный параметр нетипа:

template< typename T, int TYPEID>
struct SomeClass
{
    const char* GetClassName() const { return GetTypeIDString(TYPEID); }
};


...

SomeClass<std::string, STRING_ID> s1;
SomeClass<int, INT_ID> s2;
3
ответ дан 3 December 2019 в 19:35
поделиться

Можно попробовать что-то вроде этого (предупреждение, что это просто первое, что пришло на ум, таким образом, могут быть ошибки компиляции и т.д.)

template <typename T>
const char* GetTypeName()
{
    STATIC_ASSERT(0); // Not implemented for this type
}

#define STR(x) #x
#define GETTYPENAME(x) str(x) template <> const char* GetTypeName<x>() { return STR(x); }

// Add more as needed
GETTYPENAME(int)
GETTYPENAME(char)
GETTYPENAME(someclass)

template< typename T >
struct SomeClass
{
    const char* GetClassName() const { return GetTypeName<T>; }
}

Это будет работать на любой тип, что Вы добавляете a GETTYPENAME(type) строка для. Это имеет преимущество, что это работает, не изменяя типы, Вы интересуетесь и будете работать со встроенными и типами указателей. Это действительно имеет отличный недостаток, что Вы должны строка для каждого типа, который Вы хотите использовать.

Не используя встроенный RTTI, Вы оказываетесь перед необходимостью добавлять информацию сами где-нибудь, или ответ Brian R. Bondy или dirkgently's будет работать. Наряду с моим ответом, у Вас есть три различных места, чтобы добавить что информация:

  1. Во время создания объекта с помощью SomeClass<int>("int")
  2. В классе с помощью времени компиляции dirkgently RTTI или виртуальные функции
  3. С шаблоном с помощью моего решения.

Все три будут работать, это - просто вопрос того, где Вы закончите с наименьшим количеством головных болей обслуживания в своей ситуации.

3
ответ дан 3 December 2019 в 19:35
поделиться

Разве Вами доступ к RTTI не имеет, который означает, что Вы не можете использовать идентификатор типа (T) .name ()? Поскольку это - в значительной степени единственный способ сделать это со справкой компилятора.

1
ответ дан 3 December 2019 в 19:35
поделиться

Нет, извините.

И RTTI даже не скомпилирует, при попытке использовать его на интервале.

-1
ответ дан 3 December 2019 в 19:35
поделиться

Можно добавить немного волшебства сами. Что-то как:

#include <iostream>

#define str(x) #x
#define xstr(x) str(x)
#define make_pre(C) concat(C, <)
#define make_post(t) concat(t, >)

#define make_type(C, T) make_pre(C) ## make_post(T)
#define CTTI_REFLECTION(T, x)  static std::string my_typeid() \
                               { return xstr(make_type(T, x)); }


// the dark magic of Compile Time Type Information (TM)
#define CTTI_REFLECTION(x)  static const char * my_typeid() \
                                  { return xstr(make_type(T, x)); }

#define CREATE_TEMPLATE(class_name, type) template<> \
                                    struct class_name <type>{ \
                                        CTTI_REFLECTION(class_name, type) \
                                    }; 

// dummy, we'll specialize from this later
template<typename T> struct test_reflection;

// create an actual class
CREATE_TEMPLATE(test_reflection, int)

struct test_reflection {
  CTTI_REFLECTION(test_reflection)
};

int main(int argc, char* argv[])
{
    std::cout << test_reflection<int>::my_typeid();
}

Я сделаю инспектора a static функция (и следовательно не -const).

0
ответ дан 3 December 2019 в 19:35
поделиться

Для типов действительно ли очень важно иметь уникальные имена, или имена собираются быть сохраненными так или иначе? Если так, необходимо считать предоставление им чем-то более устойчивым, чем просто название класса, как объявлено в коде. Можно дать двум классам то же неполное имя путем помещения их в различные пространства имен. Можно также поместить два класса с тем же именем (включая квалификацию пространства имен) в двух различных DLLs в Windows, таким образом, Вам нужно определение DLL, который будет включен в имя также.

Все это зависит от того, что Вы собираетесь сделать со строками, конечно.

1
ответ дан 3 December 2019 в 19:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: