C++ std::string 到数字模板
C++ std::string to number template
我目前正在尝试实现我自己的标准输入 reader 供个人使用。我创建了一个方法来从标准输入中读取一个整数并对其有效性进行一些检查。我的想法是,我从标准输入中读取一个字符串,进行多次检查,转换为 int,进行最后一次检查,return 已读取的值。如果在检查期间发生任何错误,我将只填写一个 errorHint
以在 std::cerr
和 return std::numeric_limits<int>::min()
上打印。
我认为这个想法实现起来非常简单明了,现在我想概括这个概念并制作方法模板,所以基本上我可以在编译时选择,无论何时我需要从标准输入读取哪种类型我想要的整数(它可以是 int
、long
、long long
、unsigned long
等等,但一个整数)。为此,我创建了以下静态模板方法:
template<
class T,
class = typename std::enable_if<std::is_integral<T>::value, T>::type
>
static T getIntegerTest(std::string& strErrorHint,
T nMinimumValue = std::numeric_limits<T>::min(),
T nMaximumValue = std::numeric_limits<T>::max());
和下面几行相同的 .hpp 文件中的实现:
template<
class T,
class>
T InputReader::getIntegerTest(std::string& strErrorHint,
T nMinimumValue,
T nMaximumValue)
{
std::string strInputString;
std::cin >> strInputString;
// Do several checks
T nReturnValue = std::stoi(strInputString); /// <--- HERE!!!
// Do other checks on the returnValue
return nReturnValue;
}
现在的问题是,我想把刚刚读到的我知道在正确范围内的字符串转换成整数类型T
。我怎样才能很好地做到这一点?
特化函数对象是一种非常通用的方法,可以根据类型特征修改行为。
方法是:
为操作定义一个通用模板
专门针对极端情况的模板
通过辅助函数调用
示例:
#include <iostream>
#include <type_traits>
#include <string>
namespace detail {
/// general case
template<class Integer, typename Enable = void>
struct convert_to_integer {
Integer operator()(std::string const &str) const {
return std::stoi(str);
}
};
// special cases
template<class Integer>
struct convert_to_integer<Integer, std::enable_if_t<std::is_same<long, Integer>::value> > {
long operator()(std::string const &str) const {
return std::stol(str);
}
};
}
template<class T, class StringLike>
T to_integral(StringLike&& str)
{
using type = std::decay_t<T>;
return detail::convert_to_integer<type>()(str);
};
int main() {
std::string t1 = "6";
const char t2[] = "7";
std::cout << to_integral<int>(t1) << std::endl;
std::cout << to_integral<int>(t2) << std::endl;
// will use the specilaisation
std::cout << to_integral<long>(t1) << std::endl;
std::cout << to_integral<long>(t2) << std::endl;
// will use the default case
std::cout << to_integral<short>(t1) << std::endl;
std::cout << to_integral<short>(t2) << std::endl;
}
p.s。您的错误报告策略需要改进。建议扔一个std::runtime_error
.
我目前正在尝试实现我自己的标准输入 reader 供个人使用。我创建了一个方法来从标准输入中读取一个整数并对其有效性进行一些检查。我的想法是,我从标准输入中读取一个字符串,进行多次检查,转换为 int,进行最后一次检查,return 已读取的值。如果在检查期间发生任何错误,我将只填写一个 errorHint
以在 std::cerr
和 return std::numeric_limits<int>::min()
上打印。
我认为这个想法实现起来非常简单明了,现在我想概括这个概念并制作方法模板,所以基本上我可以在编译时选择,无论何时我需要从标准输入读取哪种类型我想要的整数(它可以是 int
、long
、long long
、unsigned long
等等,但一个整数)。为此,我创建了以下静态模板方法:
template<
class T,
class = typename std::enable_if<std::is_integral<T>::value, T>::type
>
static T getIntegerTest(std::string& strErrorHint,
T nMinimumValue = std::numeric_limits<T>::min(),
T nMaximumValue = std::numeric_limits<T>::max());
和下面几行相同的 .hpp 文件中的实现:
template<
class T,
class>
T InputReader::getIntegerTest(std::string& strErrorHint,
T nMinimumValue,
T nMaximumValue)
{
std::string strInputString;
std::cin >> strInputString;
// Do several checks
T nReturnValue = std::stoi(strInputString); /// <--- HERE!!!
// Do other checks on the returnValue
return nReturnValue;
}
现在的问题是,我想把刚刚读到的我知道在正确范围内的字符串转换成整数类型T
。我怎样才能很好地做到这一点?
特化函数对象是一种非常通用的方法,可以根据类型特征修改行为。
方法是:
为操作定义一个通用模板
专门针对极端情况的模板
通过辅助函数调用
示例:
#include <iostream>
#include <type_traits>
#include <string>
namespace detail {
/// general case
template<class Integer, typename Enable = void>
struct convert_to_integer {
Integer operator()(std::string const &str) const {
return std::stoi(str);
}
};
// special cases
template<class Integer>
struct convert_to_integer<Integer, std::enable_if_t<std::is_same<long, Integer>::value> > {
long operator()(std::string const &str) const {
return std::stol(str);
}
};
}
template<class T, class StringLike>
T to_integral(StringLike&& str)
{
using type = std::decay_t<T>;
return detail::convert_to_integer<type>()(str);
};
int main() {
std::string t1 = "6";
const char t2[] = "7";
std::cout << to_integral<int>(t1) << std::endl;
std::cout << to_integral<int>(t2) << std::endl;
// will use the specilaisation
std::cout << to_integral<long>(t1) << std::endl;
std::cout << to_integral<long>(t2) << std::endl;
// will use the default case
std::cout << to_integral<short>(t1) << std::endl;
std::cout << to_integral<short>(t2) << std::endl;
}
p.s。您的错误报告策略需要改进。建议扔一个std::runtime_error
.