我正在为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
是懒惰开发者的表现。对于这种情况,引入自己的异常类是一个很好的实践。
#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()};
}
}
现场演示