【问题标题】:C++ std::string to number templateC++ std::string 到数字模板
【发布时间】:2017-06-16 02:19:23
【问题描述】:

我目前正在尝试实现我自己的标准输入阅读器供个人使用。我创建了一种从标准输入中读取整数并对其有效性进行检查的方法。这个想法是我从标准输入中读取一个字符串,进行几次检查,转换为 int,进行最后一次检查,返回已读取的值。如果同时发生任何错误,我将填写errorHint 以在std::cerr 上打印并返回std::numeric_limits<int>::min()

我觉得这个想法实现起来非常简单直接,现在我想概括一下这个概念并制作方法模板,所以基本上我可以在编译时选择,每当我需要从标准输入中读取哪种类型的整数我想要(它可以是intlonglong longunsigned 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。我怎样才能以一种好的方式做到这一点?

【问题讨论】:

  • bool success = std::cin &gt;&gt; T_instance;,然后(另一个)范围检查...
  • 为什么不直接使用std::istringstream

标签: c++ c++11 templates std stdstring


【解决方案1】:

专门化一个函数对象是一种基于类型特征修改行为的非常通用的方法。

方法是:

  1. 为操作定义一个通用模板

  2. 专门针对极端案例的模板

  3. 通过辅助函数调用

例子:

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

附言您的错误报告策略需要工作。建议发std::runtime_error

【讨论】:

  • 感谢@Richard Hodges 的回答!很不错!我非常感激!对于异常,为什么您认为抛出异常比使用 errorHint 更好?特别是我想你会建议创建我自己的错误类型并在失败的情况下抛出那个错误类型是正确的吗?
  • @user2271691 理想情况下是您自己的错误类型,源自 std::runtime_error 或 std::invalid_argument。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-23
  • 1970-01-01
  • 1970-01-01
  • 2012-05-02
  • 1970-01-01
  • 2020-04-24
相关资源
最近更新 更多