如何在c++中打印模板typename ?



我正在为boostnumeric_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 ...
^

我认为错误信息中要求处理SourceTarget。那么有没有办法打印templatetypename?我是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是懒惰开发者的表现。对于这种情况,引入自己的异常类是一个很好的实践。

#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()};
}
}

现场演示