当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《是否可以在标准C++中打印变量的类型?》经验,为你挑选了12个好方法。

例如:

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

预期产量:

int

Howard Hinna.. 456

C++ 11更新到一个非常古老的问题:在C++中打印变量类型.

接受(和好)的答案是使用typeid(a).name(),其中a是变量名称.

现在在C++ 11中,我们decltype(x)可以将表达式转换为类型.并decltype()附带了一套非常有趣的规则.例如,decltype(a)并且decltype((a))通常是不同的类型(并且一旦这些原因暴露出于好的和可理解的原因).

我们的信任会typeid(a).name()帮助我们探索这个勇敢的新世界吗?

没有.

但是这个工具并不复杂.这是我用来回答这个问题的工具.我将比较和对比这个新工具typeid(a).name().而这个新工具实际上建立在typeid(a).name().

根本问题:

typeid(a).name()

扔掉cv-qualifiers,引用和左值/右值.例如:

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

对我来说输出:

i

我猜测MSVC输出:

int

const它已经消失了.这不是QOI(实施质量)问题.该标准规定了这种行为.

我在下面推荐的是:

template  std::string type_name();

将使用这样:

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

对我来说输出:

int const

我没有在MSVC上测试过这个. 但我欢迎那些做过的人的反馈.

C++ 11解决方案

我正在使用ipapadop__cxa_demangle推荐的非MSVC平台,他对demangle类型的回答.但在MSVC上,我相信可以解密名称(未经测试).这个核心包含一些简单的测试,可以检测,恢复和报告cv限定符以及对输入类型的引用.typeid

#include 
#include 
#ifndef _MSC_VER
#   include 
#endif
#include 
#include 
#include 

template 
std::string
type_name()
{
    typedef typename std::remove_reference::type TR;
    std::unique_ptr 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::value)
        r += " const";
    if (std::is_volatile::value)
        r += " volatile";
    if (std::is_lvalue_reference::value)
        r += "&";
    else if (std::is_rvalue_reference::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() << '\n';
    std::cout << "decltype((i)) is " << type_name() << '\n';
    std::cout << "decltype(ci) is " << type_name() << '\n';
    std::cout << "decltype((ci)) is " << type_name() << '\n';
    std::cout << "decltype(static_cast(i)) is " << type_name(i))>() << '\n';
    std::cout << "decltype(static_cast(i)) is " << type_name(i))>() << '\n';
    std::cout << "decltype(static_cast(i)) is " << type_name(i))>() << '\n';
    std::cout << "decltype(foo_lref()) is " << type_name() << '\n';
    std::cout << "decltype(foo_rref()) is " << type_name() << '\n';
    std::cout << "decltype(foo_value()) is " << type_name() << '\n';
}

输出是:

decltype(i) is int
decltype((i)) is int&
decltype(ci) is int const
decltype((ci)) is int const&
decltype(static_cast(i)) is int&
decltype(static_cast(i)) is int&&
decltype(static_cast(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(i)) is int
decltype(static_cast(i)) is int
decltype(static_cast(i)) is int
decltype(foo_lref()) is int
decltype(foo_rref()) is int
decltype(foo_value()) is int

即每个引用和cv限定符都被剥离.

C++ 14更新

就在你认为你已经找到了解决问题的解决方案的时候,总会有人突然出现并向你展示一个更好的方法.:-)

来自Jamboree的答案显示了如何在编译时在C++ 14中获取类型名称.这是一个很好的解决方案,原因如下:

    它是在编译时!

    你得到编译器本身来完成工作而不是库(甚至是std :: lib).这意味着最新语言功能(如lambdas)的结果更准确.

Jamboree的 回答并不能完全解决VS的问题,我正在调整他的代码.但是,由于这个答案得到了很多观点,花一些时间去那里并提出他的答案,没有这个,这个更新永远不会发生.

#include 
#include 
#include 
#include 

#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 
    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 
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
}

constexpr如果您仍然停留在古老的C++ 11中,此代码将自动退回.如果你用C++ 98/03在洞穴墙上画画,noexcept也会牺牲它.

C++ 17更新

在下面的评论中,Lyberta指出新的std::string_view可以取代static_string:

template 
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的常量.



1> Howard Hinna..:

C++ 11更新到一个非常古老的问题:在C++中打印变量类型.

接受(和好)的答案是使用typeid(a).name(),其中a是变量名称.

现在在C++ 11中,我们decltype(x)可以将表达式转换为类型.并decltype()附带了一套非常有趣的规则.例如,decltype(a)并且decltype((a))通常是不同的类型(并且一旦这些原因暴露出于好的和可理解的原因).

我们的信任会typeid(a).name()帮助我们探索这个勇敢的新世界吗?

没有.

但是这个工具并不复杂.这是我用来回答这个问题的工具.我将比较和对比这个新工具typeid(a).name().而这个新工具实际上建立在typeid(a).name().

根本问题:

typeid(a).name()

扔掉cv-qualifiers,引用和左值/右值.例如:

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

对我来说输出:

i

我猜测MSVC输出:

int

const它已经消失了.这不是QOI(实施质量)问题.该标准规定了这种行为.

我在下面推荐的是:

template  std::string type_name();

将使用这样:

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

对我来说输出:

int const

我没有在MSVC上测试过这个. 但我欢迎那些做过的人的反馈.

C++ 11解决方案

我正在使用ipapadop__cxa_demangle推荐的非MSVC平台,他对demangle类型的回答.但在MSVC上,我相信可以解密名称(未经测试).这个核心包含一些简单的测试,可以检测,恢复和报告cv限定符以及对输入类型的引用.typeid

#include 
#include 
#ifndef _MSC_VER
#   include 
#endif
#include 
#include 
#include 

template 
std::string
type_name()
{
    typedef typename std::remove_reference::type TR;
    std::unique_ptr 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::value)
        r += " const";
    if (std::is_volatile::value)
        r += " volatile";
    if (std::is_lvalue_reference::value)
        r += "&";
    else if (std::is_rvalue_reference::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() << '\n';
    std::cout << "decltype((i)) is " << type_name() << '\n';
    std::cout << "decltype(ci) is " << type_name() << '\n';
    std::cout << "decltype((ci)) is " << type_name() << '\n';
    std::cout << "decltype(static_cast(i)) is " << type_name(i))>() << '\n';
    std::cout << "decltype(static_cast(i)) is " << type_name(i))>() << '\n';
    std::cout << "decltype(static_cast(i)) is " << type_name(i))>() << '\n';
    std::cout << "decltype(foo_lref()) is " << type_name() << '\n';
    std::cout << "decltype(foo_rref()) is " << type_name() << '\n';
    std::cout << "decltype(foo_value()) is " << type_name() << '\n';
}

输出是:

decltype(i) is int
decltype((i)) is int&
decltype(ci) is int const
decltype((ci)) is int const&
decltype(static_cast(i)) is int&
decltype(static_cast(i)) is int&&
decltype(static_cast(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(i)) is int
decltype(static_cast(i)) is int
decltype(static_cast(i)) is int
decltype(foo_lref()) is int
decltype(foo_rref()) is int
decltype(foo_value()) is int

即每个引用和cv限定符都被剥离.

C++ 14更新

就在你认为你已经找到了解决问题的解决方案的时候,总会有人突然出现并向你展示一个更好的方法.:-)

来自Jamboree的答案显示了如何在编译时在C++ 14中获取类型名称.这是一个很好的解决方案,原因如下:

    它是在编译时!

    你得到编译器本身来完成工作而不是库(甚至是std :: lib).这意味着最新语言功能(如lambdas)的结果更准确.

Jamboree的 回答并不能完全解决VS的问题,我正在调整他的代码.但是,由于这个答案得到了很多观点,花一些时间去那里并提出他的答案,没有这个,这个更新永远不会发生.

#include 
#include 
#include 
#include 

#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 
    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 
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
}

constexpr如果您仍然停留在古老的C++ 11中,此代码将自动退回.如果你用C++ 98/03在洞穴墙上画画,noexcept也会牺牲它.

C++ 17更新

在下面的评论中,Lyberta指出新的std::string_view可以取代static_string:

template 
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的常量.


@AngelusMortis:因为英语与C++代码相比模糊/含糊不清,我建议您将其复制/粘贴到您感兴趣的特定类型的测试用例中,并使用您感兴趣的特定编译器,并回复更多如果结果令人惊讶和/或不满意,请详细说明.
VS 14 CTP打印出正确的类型,我只需添加一个`#include `行.
为什么模板 std :: string type_name()?你为什么不传递一个类型作为参数?
我相信我的理由是有时我*只*有一个类型(例如推导出的模板参数),我不想人为地构造其中一个来获得类型(虽然这些天`declval`会做工作).
@HowardHinnant您可以使用`std :: string_view`而不是`static_string`吗?
您能使C ++ 17不使用幻数,而是让读者理解那些偏移量的东西吗?

2> Konrad Rudol..:

尝试:

#include 

// …
std::cout << typeid(a).name() << '\n';

您可能必须在编译器选项中激活RTTI才能使其生效.另外,这个输出取决于编译器.它可能是原始类型名称或名称重整符号或介于两者之间的任何内容.


@Destructor提供标准化的名称修改格式可能会给人一种印象,即两个不同编译器构建的二进制文件之间的互操作性是可能的和/或安全的.因为C++没有标准的ABI,标准的名称修改方案将毫无意义,并且可能具有误导性和危险性.
为什么name()函数返回的字符串是实现定义的?
@PravasiMeet据我所知,没有充分的理由.委员会根本不想强迫编译器实现者进入特定的技术方向 - 事后看来可能是一个错误.
是否有可用于启用RTTI的标志?也许你可以把你的答案包括在内.

3> NickV..:

如果你只想要编译时间信息(例如用于调试),那么非常难看

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'


感谢您将错误用作C++功能!
@KarlP很公平,这有点令人费解,这也有效:)```auto testVar = std :: make_tuple(1,1.0,"abc"); decltype(testVar):: foo = 1;```

4> mdec..:

别忘了包括

我相信你所指的是运行时类型识别.你可以做到这一点.

#include 
#include 

using namespace std;

int main() {
  int i;
  cout << typeid(i).name();
  return 0;
}



5> paercebal..:

请注意,C++的RTTI功能生成的名称不可移植.例如,班级

MyNamespace::CMyContainer

将具有以下名称:

// MSVC 2003:
class MyNamespace::CMyContainer[int,class test_MyNamespace::CMyObject]
// G++ 4.2:
N8MyNamespace8CMyContainerIiN13test_MyNamespace9CMyObjectEEE

因此,您无法使用此信息进行序列化.但是,仍然可以将typeid(a).name()属性用于日志/调试目的



6> Nick..:

您可以使用模板.

template  const char* typeof(T&) { return "unknown"; }    // default
template<> const char* typeof(int&) { return "int"; }
template<> const char* typeof(float&) { return "float"; }

在上面的示例中,当类型不匹配时,它将打印"未知".


不会为短裤和字符打印"int"吗?和"浮动"双打?
@gartenriese我想的很多,但"互联网"在某些时候可能会有同样的问题.

7> 康桓瑋..:

根据霍华德的解决方案,如果您不想要幻数,我认为这是代表并且看起来直观的好方法:

template 
constexpr auto type_name()
{
    std::string_view name, prefix, suffix;
#ifdef __clang__
    name = __PRETTY_FUNCTION__;
    prefix = "auto type_name() [T = ";
    suffix = "]";
#elif defined(__GNUC__)
    name = __PRETTY_FUNCTION__;
    prefix = "constexpr auto type_name() [with T = ";
    suffix = "]";
#elif defined(_MSC_VER)
    name = __FUNCSIG__;
    prefix = "auto __cdecl type_name<";
    suffix = ">(void)";
#endif
    name.remove_prefix(prefix.size());
    name.remove_suffix(suffix.size());
    return name;
}   



8> ipapadop..:

如上所述,typeid().name()可能会返回一个受损的名称.在GCC(和其他一些编译器)中,您可以使用以下代码解决它:

#include 
#include 
#include 
#include 

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;

}



9> Greg Hewgill..:

你可以使用traits类.就像是:

#include 
using namespace std;

template  class type_name {
public:
    static const char *name;
};

#define DECLARE_TYPE_NAME(x) template<> const char *type_name::name = #x;
#define GET_TYPE_NAME(x) (type_name::name)

DECLARE_TYPE_NAME(int);

int main()
{
    int a = 12;
    cout << GET_TYPE_NAME(a) << endl;
}

DECLARE_TYPE_NAME定义的存在是为了让您的生活更容易在这个声明traits类为所有你期望需要的类型.

这可能比涉及的解决方案更有用,typeid因为您可以控制输出.例如,在我的编译器上使用typeidfor long long给出"x".



10> 小智..:

在C++ 11中,我们有decltype.标准c ++中无法显示使用decltype声明的确切类型的变量.我们可以使用boost typeindex即type_id_with_cvr(cvr代表const,volatile,reference)来打印类型,如下所示.

#include 
#include 

using namespace std;
using boost::typeindex::type_id_with_cvr;

int main() {
  int i = 0;
  const int ci = 0;
  cout << "decltype(i) is " << type_id_with_cvr().pretty_name() << '\n';
  cout << "decltype((i)) is " << type_id_with_cvr().pretty_name() << '\n';
  cout << "decltype(ci) is " << type_id_with_cvr().pretty_name() << '\n';
  cout << "decltype((ci)) is " << type_id_with_cvr().pretty_name() << '\n';
  cout << "decltype(std::move(i)) is " << type_id_with_cvr().pretty_name() << '\n';
  cout << "decltype(std::static_cast(i)) is " << type_id_with_cvr(i))>().pretty_name() << '\n';
  return 0;
}



11> James Hopkin..:

涉及RTTI(typeid)的其他答案可能就是你想要的,只要:

你可以承受内存开销(对于某些编译器来说可能相当大)

您的编译器返回的类名是有用的

另一种选择(类似于Greg Hewgill的回答)是构建一个特征的编译时表.

template  struct type_as_string;

// declare your Wibble type (probably with definition of Wibble)
template <>
struct type_as_string
{
    static const char* const value = "Wibble";
};

请注意,如果将声明包装在宏中,由于逗号,您将无法为使用多个参数(例如std :: map)的模板类型声明名称.

要访问变量类型的名称,您只需要

template 
const char* get_type_as_string(const T&)
{
    return type_as_string::value;
}


static const char*value ="Wibble"; 你做不到那个伙伴:)

12> Jahid..:

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

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

    return Type;}

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

例:

#include 



class MyClass{};


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


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

输出:

int
String
MyClass

推荐阅读
勤奋的瞌睡猪_715
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有