是否能够在标准C ++中打印变量的类型?

例如: ios

int a = 12;
cout << typeof(a) << endl;

预期产量: 函数

int

#1楼

很是丑陋,可是若是您只想要编译时间信息(例如,用于调试),则能够达到目的: 工具

auto testVar = std::make_tuple(1, 1.0, "abc");
decltype(testVar)::foo= 1;

返回值: 学习

Compilation finished with errors:
source.cpp: In function 'int main()':
source.cpp:5:19: error: 'foo' is not a member of 'std::tuple<int, double, const char*>'

#2楼

如前所述, typeid().name()可能返回错误的名称。 在GCC(和其余一些编译器)中,您可使用如下代码来解决它: 测试

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

namespace some_namespace { namespace another_namespace {

  class my_class { };

} }

int main() {
  typedef some_namespace::another_namespace::my_class my_type;
  // mangled
  std::cout << typeid(my_type).name() << std::endl;

  // unmangled
  int status = 0;
  char* demangled = abi::__cxa_demangle(typeid(my_type).name(), 0, 0, &status);

  switch (status) {
    case -1: {
      // could not allocate memory
      std::cout << "Could not allocate memory" << std::endl;
      return -1;
    } break;
    case -2: {
      // invalid name under the C++ ABI mangling rules
      std::cout << "Invalid name" << std::endl;
      return -1;
    } break;
    case -3: {
      // invalid argument
      std::cout << "Invalid argument to demangle()" << std::endl;
      return -1;
    } break;
 }
 std::cout << demangled << std::endl;

 free(demangled);

 return 0;

} spa


#3楼

C ++ 11更新为一个很是老的问题:在C ++中打印变量类型。 调试

公认的(也是好的)答案是使用typeid(a).name() ,其中a是变量名。 code

如今在C ++ 11中,咱们有了decltype(x) ,它能够将表达式转换为类型。 并且decltype()带有其本身的一组很是有趣的规则。 例如, decltype(a)decltype((a))一般将是不一样的类型(而且出于良好且易于理解的缘由,一旦暴露了这些缘由)。 ip

咱们可信赖的typeid(a).name()帮助咱们探索这个勇敢的新世界吗? ci

没有。

可是将不会那么复杂的工具。 这就是我用来回答这个问题的工具。 我将把这个新工具与typeid(a).name()进行比较和对比。 这个新工具其实是在typeid(a).name()之上构建的。

基本问题:

typeid(a).name()

丢弃cv限定词,引用和左值/右值-ness。 例如:

const int ci = 0;
std::cout << typeid(ci).name() << '\n';

对我来讲输出:

i

我猜对MSVC输出:

int

const不见了。 这不是QOI(实施质量)问题。 该标准规定了这种行为。

我在下面推荐的是:

template <typename T> std::string type_name();

能够这样使用:

const int ci = 0;
std::cout << type_name<decltype(ci)>() << '\n';

对我来讲:

int const

<disclaimer>我还没有在MSVC上对此进行测试。 </disclaimer>可是,我欢迎那些提供反馈的人。

C ++ 11解决方案

根据ipapadop在他对demangle类型的回答中的建议,我正在将__cxa_demangle用于非MSVC平台。 可是在MSVC上,我相信typeid能够拆解名称(未经测试)。 这个核心围绕着一些简单的测试,这些测试能够检测,恢复和报告简历限定符以及对输入类型的引用。

#include <type_traits>
#include <typeinfo>
#ifndef _MSC_VER
#   include <cxxabi.h>
#endif
#include <memory>
#include <string>
#include <cstdlib>

template <class T>
std::string
type_name()
{
    typedef typename std::remove_reference<T>::type TR;
    std::unique_ptr<char, void(*)(void*)> own
           (
#ifndef _MSC_VER
                abi::__cxa_demangle(typeid(TR).name(), nullptr,
                                           nullptr, nullptr),
#else
                nullptr,
#endif
                std::free
           );
    std::string r = own != nullptr ? own.get() : typeid(TR).name();
    if (std::is_const<TR>::value)
        r += " const";
    if (std::is_volatile<TR>::value)
        r += " volatile";
    if (std::is_lvalue_reference<T>::value)
        r += "&";
    else if (std::is_rvalue_reference<T>::value)
        r += "&&";
    return r;
}

结果

使用此解决方案,我能够作到这一点:

int& foo_lref();
int&& foo_rref();
int foo_value();

int
main()
{
    int i = 0;
    const int ci = 0;
    std::cout << "decltype(i) is " << type_name<decltype(i)>() << '\n';
    std::cout << "decltype((i)) is " << type_name<decltype((i))>() << '\n';
    std::cout << "decltype(ci) is " << type_name<decltype(ci)>() << '\n';
    std::cout << "decltype((ci)) is " << type_name<decltype((ci))>() << '\n';
    std::cout << "decltype(static_cast<int&>(i)) is " << type_name<decltype(static_cast<int&>(i))>() << '\n';
    std::cout << "decltype(static_cast<int&&>(i)) is " << type_name<decltype(static_cast<int&&>(i))>() << '\n';
    std::cout << "decltype(static_cast<int>(i)) is " << type_name<decltype(static_cast<int>(i))>() << '\n';
    std::cout << "decltype(foo_lref()) is " << type_name<decltype(foo_lref())>() << '\n';
    std::cout << "decltype(foo_rref()) is " << type_name<decltype(foo_rref())>() << '\n';
    std::cout << "decltype(foo_value()) is " << type_name<decltype(foo_value())>() << '\n';
}

输出为:

decltype(i) is int
decltype((i)) is int&
decltype(ci) is int const
decltype((ci)) is int const&
decltype(static_cast<int&>(i)) is int&
decltype(static_cast<int&&>(i)) is int&&
decltype(static_cast<int>(i)) is int
decltype(foo_lref()) is int&
decltype(foo_rref()) is int&&
decltype(foo_value()) is int

注意(例如) decltype(i)decltype((i))之间的区别。 前者是i 声明的类型。 后者是表达式 i的“类型”。 (表达式从不具备引用类型,但按照惯例, decltype表示具备左值引用的左值表达式)。

所以,除了探索和调试本身的代码外,该工具仍是学习decltype的绝佳工具。

相反,若是我仅在typeid(a).name()上构建它,而不添加回丢失的cv限定词或引用,则输出将是:

decltype(i) is int
decltype((i)) is int
decltype(ci) is int
decltype((ci)) is int
decltype(static_cast<int&>(i)) is int
decltype(static_cast<int&&>(i)) is int
decltype(static_cast<int>(i)) is int
decltype(foo_lref()) is int
decltype(foo_rref()) is int
decltype(foo_value()) is int

即剥夺了每一个参考和简历限定词。

C ++ 14更新

只是当您认为本身已肯定解决问题的方法时,总会有人无所事事,向您展现更好的方法。 :-)

来自Jamboree的 答案显示了如何在编译时获取C ++ 14中的类型名称。 这是一个出色的解决方案,其缘由以下:

  1. 在编译时!
  2. 您可让编译器自己代替库(甚至是std :: lib)来执行此工做。 这意味着使用最新的语言功能(例如lambda)可得到更准确的结果。

Jamboree的 答案并不能彻底解决VS的所有问题,我须要对他的代码进行一些调整。 可是,因为这个答案获得了不少人的承认,所以,请花一些时间浏览该地点并投票支持他的答案,不然,这个更新就永远不会发生。

#include <cstddef>
#include <stdexcept>
#include <cstring>
#include <ostream>

#ifndef _MSC_VER
#  if __cplusplus < 201103
#    define CONSTEXPR11_TN
#    define CONSTEXPR14_TN
#    define NOEXCEPT_TN
#  elif __cplusplus < 201402
#    define CONSTEXPR11_TN constexpr
#    define CONSTEXPR14_TN
#    define NOEXCEPT_TN noexcept
#  else
#    define CONSTEXPR11_TN constexpr
#    define CONSTEXPR14_TN constexpr
#    define NOEXCEPT_TN noexcept
#  endif
#else  // _MSC_VER
#  if _MSC_VER < 1900
#    define CONSTEXPR11_TN
#    define CONSTEXPR14_TN
#    define NOEXCEPT_TN
#  elif _MSC_VER < 2000
#    define CONSTEXPR11_TN constexpr
#    define CONSTEXPR14_TN
#    define NOEXCEPT_TN noexcept
#  else
#    define CONSTEXPR11_TN constexpr
#    define CONSTEXPR14_TN constexpr
#    define NOEXCEPT_TN noexcept
#  endif
#endif  // _MSC_VER

class static_string
{
    const char* const p_;
    const std::size_t sz_;

public:
    typedef const char* const_iterator;

    template <std::size_t N>
    CONSTEXPR11_TN static_string(const char(&a)[N]) NOEXCEPT_TN
        : p_(a)
        , sz_(N-1)
        {}

    CONSTEXPR11_TN static_string(const char* p, std::size_t N) NOEXCEPT_TN
        : p_(p)
        , sz_(N)
        {}

    CONSTEXPR11_TN const char* data() const NOEXCEPT_TN {return p_;}
    CONSTEXPR11_TN std::size_t size() const NOEXCEPT_TN {return sz_;}

    CONSTEXPR11_TN const_iterator begin() const NOEXCEPT_TN {return p_;}
    CONSTEXPR11_TN const_iterator end()   const NOEXCEPT_TN {return p_ + sz_;}

    CONSTEXPR11_TN char operator[](std::size_t n) const
    {
        return n < sz_ ? p_[n] : throw std::out_of_range("static_string");
    }
};

inline
std::ostream&
operator<<(std::ostream& os, static_string const& s)
{
    return os.write(s.data(), s.size());
}

template <class T>
CONSTEXPR14_TN
static_string
type_name()
{
#ifdef __clang__
    static_string p = __PRETTY_FUNCTION__;
    return static_string(p.data() + 31, p.size() - 31 - 1);
#elif defined(__GNUC__)
    static_string p = __PRETTY_FUNCTION__;
#  if __cplusplus < 201402
    return static_string(p.data() + 36, p.size() - 36 - 1);
#  else
    return static_string(p.data() + 46, p.size() - 46 - 1);
#  endif
#elif defined(_MSC_VER)
    static_string p = __FUNCSIG__;
    return static_string(p.data() + 38, p.size() - 38 - 7);
#endif
}

若是您仍然停留在古老的C ++ 11中,则此代码将在constexpr上自动回退。 并且,若是您要使用C ++ noexcept在洞穴墙壁上绘画,那么noexcept也将被牺牲。

C ++ 17更新

在下面的评论中, Lyberta指出新的std::string_view能够代替static_string

template <class T>
constexpr
std::string_view
type_name()
{
    using namespace std;
#ifdef __clang__
    string_view p = __PRETTY_FUNCTION__;
    return string_view(p.data() + 34, p.size() - 34 - 1);
#elif defined(__GNUC__)
    string_view p = __PRETTY_FUNCTION__;
#  if __cplusplus < 201402
    return string_view(p.data() + 36, p.size() - 36 - 1);
#  else
    return string_view(p.data() + 49, p.find(';', 49) - 49);
#  endif
#elif defined(_MSC_VER)
    string_view p = __FUNCSIG__;
    return string_view(p.data() + 84, p.size() - 84 - 7);
#endif
}

感谢Jive Dadson在下面的评论中所作的很是出色的侦探工做,我已经更新了VS的常数。

更新:

请确保在下面检查此重写,以消除我最新公式中没法理解的幻数。


#4楼

我喜欢尼克的方法,一个完整的表格多是这样的(对于全部基本数据类型):

template <typename T> const char* typeof(T&) { return "unknown"; }    // default
template<> const char* typeof(int&) { return "int"; }
template<> const char* typeof(short&) { return "short"; }
template<> const char* typeof(long&) { return "long"; }
template<> const char* typeof(unsigned&) { return "unsigned"; }
template<> const char* typeof(unsigned short&) { return "unsigned short"; }
template<> const char* typeof(unsigned long&) { return "unsigned long"; }
template<> const char* typeof(float&) { return "float"; }
template<> const char* typeof(double&) { return "double"; }
template<> const char* typeof(long double&) { return "long double"; }
template<> const char* typeof(std::string&) { return "String"; }
template<> const char* typeof(char&) { return "char"; }
template<> const char* typeof(signed char&) { return "signed char"; }
template<> const char* typeof(unsigned char&) { return "unsigned char"; }
template<> const char* typeof(char*&) { return "char*"; }
template<> const char* typeof(signed char*&) { return "signed char*"; }
template<> const char* typeof(unsigned char*&) { return "unsigned char*"; }

#5楼

一个比我之前的解决方案更通用的解决方案,没有函数重载:

template<typename T>
std::string TypeOf(T){
    std::string Type="unknown";
    if(std::is_same<T,int>::value) Type="int";
    if(std::is_same<T,std::string>::value) Type="String";
    if(std::is_same<T,MyClass>::value) Type="MyClass";

    return Type;}

MyClass是用户定义的类。 也能够在此处添加更多条件。

例:

#include <iostream>



class MyClass{};


template<typename T>
std::string TypeOf(T){
    std::string Type="unknown";
    if(std::is_same<T,int>::value) Type="int";
    if(std::is_same<T,std::string>::value) Type="String";
    if(std::is_same<T,MyClass>::value) Type="MyClass";
    return Type;}


int main(){;
    int a=0;
    std::string s="";
    MyClass my;
    std::cout<<TypeOf(a)<<std::endl;
    std::cout<<TypeOf(s)<<std::endl;
    std::cout<<TypeOf(my)<<std::endl;

    return 0;}

输出:

int
String
MyClass
相关文章
相关标签/搜索