如何在 C++ 中打印模板类型名?
how to print template typename in c++?
我正在为 boost
numeric_cast
编写包装器,包装器函数类似于:
#include <boost/numeric/conversion/cast.hpp>
#include <stdexcept>
template <typename Source, typename Target>
Target numeric_cast(Source src)
{
try
{
// calling boost numeric_cast here
}
catch(boost::numeric::bad_numeric_cast& e)
{
throw std::runtime_error("numeric_cast failed, fromType: " + Source + " toType: " + Target);
}
}
我遇到了这个错误:
error: expected primary-expression before ‘(’ token
throw std::runtime_error("numeric_cast failed ...
^
我认为错误是要求处理错误消息中的 Source
和 Target
。那么有没有办法打印template
typename
呢?我是 c++ 的初学者,所以这可能是一个愚蠢的问题...
您可以使用typeid(T).name()
获取模板参数的原始字符串:
#include <boost/numeric/conversion/cast.hpp>
#include <stdexcept>
#include <typeinfo>
template <typename Source, typename Target>
Target numeric_cast(Source src)
{
try
{
// calling boost numeric_cast here
}
catch(boost::numeric::bad_numeric_cast& e)
{
throw (std::string("numeric_cast failed, fromType: ") +
typeid(Source).name() + " toType: " + typeid(Target).name());
}
}
请注意字符串文字 "numeric_cast failed, fromType:"
应该是 std::string
类型以支持 '+'
运算符。
首先你应该翻转模板参数。 Source
可以自动推导,另一方面 Target
不能。所以 Target
必须明确提供并且应该在模板参数列表中排在第一位,所以 Source
无论如何都可以推导出来。
第二个问题是不能像那样添加字符串文字(这来自 C)。要在 C++ 中构建复杂的字符串,请使用 std::ostringstream
.
要获取类型名称信息,您可以使用 typeid
。由于此名称已损坏并且您已经使用了 boost
,因此您可以使用 boost
去除该名称并获得很好的人类可读类型名称。
最后一件事:直接使用std::runtime_error
是开发者懒惰的体现。为此类情况引入自己的例外 class 是一种很好的做法。
#include <iostream>
#include <sstream>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/core/demangle.hpp>
#include <typeinfo>
#include <stdexcept>
template<typename T>
std::string typeName()
{
return boost::core::demangle(typeid(T).name());
}
// this is used to bind all exceptions related to local library
class MyLibExceptions : public std::exception
{};
class BadNumericCast : public MyLibExceptions
{
public:
template<typename Target, typename Source>
BadNumericCast(Source arg, Target, const char *extra)
{
std::ostringstream desc;
desc << extra << " from type: '" << typeName<Source>()
<< "' with value: " << arg
<< " to type: '" << typeName<Target>() << '\'';
mDesc = desc.str();
}
const char* what() const noexcept override
{
return mDesc.c_str();
}
private:
std::string mDesc;
};
template <typename Target, typename Source>
Target numeric_cast(Source arg)
{
try
{
return boost::numeric::converter<Target, Source>::convert(arg);
}
catch(boost::numeric::bad_numeric_cast& e)
{
throw BadNumericCast{arg, Target{}, e.what()};
}
}
我正在为 boost
numeric_cast
编写包装器,包装器函数类似于:
#include <boost/numeric/conversion/cast.hpp>
#include <stdexcept>
template <typename Source, typename Target>
Target numeric_cast(Source src)
{
try
{
// calling boost numeric_cast here
}
catch(boost::numeric::bad_numeric_cast& e)
{
throw std::runtime_error("numeric_cast failed, fromType: " + Source + " toType: " + Target);
}
}
我遇到了这个错误:
error: expected primary-expression before ‘(’ token
throw std::runtime_error("numeric_cast failed ...
^
我认为错误是要求处理错误消息中的 Source
和 Target
。那么有没有办法打印template
typename
呢?我是 c++ 的初学者,所以这可能是一个愚蠢的问题...
您可以使用typeid(T).name()
获取模板参数的原始字符串:
#include <boost/numeric/conversion/cast.hpp>
#include <stdexcept>
#include <typeinfo>
template <typename Source, typename Target>
Target numeric_cast(Source src)
{
try
{
// calling boost numeric_cast here
}
catch(boost::numeric::bad_numeric_cast& e)
{
throw (std::string("numeric_cast failed, fromType: ") +
typeid(Source).name() + " toType: " + typeid(Target).name());
}
}
请注意字符串文字 "numeric_cast failed, fromType:"
应该是 std::string
类型以支持 '+'
运算符。
首先你应该翻转模板参数。 Source
可以自动推导,另一方面 Target
不能。所以 Target
必须明确提供并且应该在模板参数列表中排在第一位,所以 Source
无论如何都可以推导出来。
第二个问题是不能像那样添加字符串文字(这来自 C)。要在 C++ 中构建复杂的字符串,请使用 std::ostringstream
.
要获取类型名称信息,您可以使用 typeid
。由于此名称已损坏并且您已经使用了 boost
,因此您可以使用 boost
去除该名称并获得很好的人类可读类型名称。
最后一件事:直接使用std::runtime_error
是开发者懒惰的体现。为此类情况引入自己的例外 class 是一种很好的做法。
#include <iostream>
#include <sstream>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/core/demangle.hpp>
#include <typeinfo>
#include <stdexcept>
template<typename T>
std::string typeName()
{
return boost::core::demangle(typeid(T).name());
}
// this is used to bind all exceptions related to local library
class MyLibExceptions : public std::exception
{};
class BadNumericCast : public MyLibExceptions
{
public:
template<typename Target, typename Source>
BadNumericCast(Source arg, Target, const char *extra)
{
std::ostringstream desc;
desc << extra << " from type: '" << typeName<Source>()
<< "' with value: " << arg
<< " to type: '" << typeName<Target>() << '\'';
mDesc = desc.str();
}
const char* what() const noexcept override
{
return mDesc.c_str();
}
private:
std::string mDesc;
};
template <typename Target, typename Source>
Target numeric_cast(Source arg)
{
try
{
return boost::numeric::converter<Target, Source>::convert(arg);
}
catch(boost::numeric::bad_numeric_cast& e)
{
throw BadNumericCast{arg, Target{}, e.what()};
}
}