Указатель NULL
- это тот, который указывает на никуда. Когда вы разыскиваете указатель p
, вы говорите «дайте мне данные в месте, хранящемся в« p ». Когда p
является нулевым указателем, местоположение, хранящееся в p
, является nowhere
, вы говорите «Дайте мне данные в месте« нигде ». Очевидно, он не может этого сделать, поэтому он выбрасывает NULL pointer exception
.
В общем, это потому, что что-то не было правильно инициализировано.
Другие ответы, включающие RTTI (идентификатор типа), вероятно, что Вы хотите, пока:
, альтернатива, (подобный ответу Greg Hewgill), должна создать таблицу времени компиляции черт.
template <typename T> struct type_as_string;
// declare your Wibble type (probably with definition of Wibble)
template <>
struct type_as_string<Wibble>
{
static const char* const value = "Wibble";
};
знать, что при обертывании объявлений в макрос Вы испытаете затруднения при объявлении названий шаблонных типов, берущих больше чем один параметр (например, станд.:: карта), из-за запятой.
Для доступа к названию типа переменной все, в чем Вы нуждаетесь,
template <typename T>
const char* get_type_as_string(const T&)
{
return type_as_string<T>::value;
}
Вы могли использовать класс черт для этого. Что-то как:
#include <iostream>
using namespace std;
template <typename T> class type_name {
public:
static const char *name;
};
#define DECLARE_TYPE_NAME(x) template<> const char *type_name<x>::name = #x;
#define GET_TYPE_NAME(x) (type_name<typeof(x)>::name)
DECLARE_TYPE_NAME(int);
int main()
{
int a = 12;
cout << GET_TYPE_NAME(a) << endl;
}
Эти DECLARE_TYPE_NAME
определяют, существует для создания жизни легче в объявлении этого класса черт для всех типов, в которых Вы ожидаете нуждаться.
Это могло бы быть более полезно, чем решения, включающие typeid
, потому что Вы добираетесь для управления выводом. Например, использование typeid
для long long
на моем компиляторе дает "x".
Можно использовать шаблоны.
template <typename T> const char* typeof(T&) { return "unknown"; } // default
template<> const char* typeof(int&) { return "int"; }
template<> const char* typeof(float&) { return "float"; }
В примере выше, когда тип не будет подобран, он распечатает "неизвестный".
Обратите внимание, что имена, сгенерированные функцией RTTI C++, не портативны. Например, класс
MyNamespace::CMyContainer<int, test_MyNamespace::CMyObject>
будет иметь следующие имена:
// MSVC 2003:
class MyNamespace::CMyContainer[int,class test_MyNamespace::CMyObject]
// G++ 4.2:
N8MyNamespace8CMyContainerIiN13test_MyNamespace9CMyObjectEEE
, Таким образом, Вы не можете использовать эту информацию для сериализации. Но тем не менее, идентификатор типа (a) .name () свойство может все еще использоваться в целях журнала/отладки
Не забывайте включать <typeinfo>
, я верю тому, к чему Вы обращаетесь, динамическая идентификация типов. Можно достигнуть вышеупомянутого путем выполнения.
#include <iostream>
#include <typeinfo>
using namespace std;
int main() {
int i;
cout << typeid(i).name();
return 0;
}
Попытка:
#include <typeinfo>
// …
std::cout << typeid(a).name() << '\n';
Вам, возможно, придется активировать RTTI в Ваших параметрах компилятора для этого для работы. Кроме того, вывод этого зависит от компилятора. Это могло бы быть необработанное имя типа или символ искажения имени или что-либо промежуточное.
Howard Hinnant используемые магические числа для извлечения имени типа. еє · жЎ “з‘‹ предложенный строковый префикс и суффикс. Но префикс/суффикс продолжает изменяться. С вЂњprobe_type” type_name автоматически вычисляет префикс и суффиксные размеры для “probe_type” для извлечения имени типа:
#include <iostream>
#include <string_view>
using namespace std;
class probe_type;
template <typename T>
constexpr string_view type_name() {
string_view probe_type_name("class probe_type");
const string_view class_specifier("class");
string_view name;
#ifdef __clang__
name = __PRETTY_FUNCTION__;
probe_type_name.remove_prefix(class_specifier.length());
#elif defined(__GNUC__)
name = __PRETTY_FUNCTION__;
probe_type_name.remove_prefix(class_specifier.length());
#elif defined(_MSC_VER)
name = __FUNCSIG__;
#endif
if (name.find(probe_type_name) != string_view::npos)
return name;
const string_view probe_type_raw_name = type_name<probe_type>();
const size_t prefix_size = probe_type_raw_name.find(probe_type_name);
name.remove_prefix(prefix_size);
name.remove_suffix(probe_type_raw_name.length() - prefix_size - probe_type_name.length());
return name;
}
class test;
int main() {
cout << type_name<test>() << endl;
cout << type_name<const int*&>() << endl;
cout << type_name<unsigned int>() << endl;
const int ic = 42;
const int* pic = ⁣
const int*& rpic = pic;
cout << type_name<decltype(ic)>() << endl;
cout << type_name<decltype(pic)>() << endl;
cout << type_name<decltype(rpic)>() << endl;
cout << type_name<probe_type>() << endl;
}
Вывод
gcc 10.0.0 20 190 919 Wandbox:
test
const int *&
unsigned int
const int
const int *
const int *&
constexpr std::string_view type_name() [with T = probe_type; std::string_view = std::basic_string_view<char>]
лязг 10.0.0 Wandbox:
test
const int *&
unsigned int
const int
const int *
const int *&
std::__1::string_view type_name() [T = probe_type]
версия 16.3.3 VS 2019:
class test
const int*&
unsigned int
const int
const int*
const int*&
class std::basic_string_view<char,struct std::char_traits<char> > __cdecl type_name<class probe_type>(void)