模板友好字符串到 C++ 中的数字

Mir*_*pas 52 c++ string-conversion

在 C++ 标准库中有将字符串转换为数字类型的函数:

stoi
stol
stoll
stoul
stoull
stof
stod
stold
Run Code Online (Sandbox Code Playgroud)

但我发现在模板代码中使用它们很乏味。为什么没有模板函数,例如:

template<typename T>
T sto(...)
Run Code Online (Sandbox Code Playgroud)

将字符串转换为数字类型?

我没有看到任何不拥有它们的技术原因,但也许我错过了一些东西。它们可以专门用于调用底层命名函数并使用enable_if/concepts禁用非数字类型。

标准库中是否有任何模板友好的替代方案可以将字符串转换为数字类型,反之亦然?

Gui*_*cot 43

为什么没有模板函数,例如:

C++17 有这样的通用字符串到数字函数,但命名不同。他们使用了std::from_chars,它对所有数字类型都重载了。

如您所见,第一个重载将任何整数类型作为输出参数,并在可能的情况下为其分配值。

它可以像这样使用:

template<typename Numeric>
void stuff(std::string_view s) {
    auto value = Numeric{};

    auto [ptr, error] = std::from_chars(s.data(), s.data() + s.size(), value);

    if (error != std::errc{}) {
        // error with the conversion
    } else {
        // conversion successful, do stuff with value
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,它可以在通用上下文中工作。

  • C++现在有解构了吗?:o [结构化绑定声明](https://en.cppreference.com/w/cpp/language/structured_binding) (5认同)

Nat*_*ica 14

它不是一个模板,它不适用于语言环境,但如果这不是一个显示停止器,那么 C++17 已经拥有你想要的: std::from_chars

所有整数和浮点类型都有重载,接口是相同的,除了最后一个参数对于整数和浮点类型分别不同(但如果默认值很好,那么你不需要改变任何东西)。因为这不是区域设置感知功能,所以它也非常快。它将击败任何其他字符串到值转换函数,通常是数量级。

Stephan T. Lavavej有一个非常好的 CPPCON 视频<charconv>(标题from_chars位于),您可以在此处观看有关其使用和性能的视频:https : //www.youtube.com/watch?v= 4P_kbF0EbZM


for*_*818 10

你不会得到太多,因为在这样的表达中

int x = sto("1");
Run Code Online (Sandbox Code Playgroud)

没有(简单的)方法可以推导出模板参数所需的类型。你必须写

int x = sto<int>("1");
Run Code Online (Sandbox Code Playgroud)

这在某种程度上违背了提供通用函数的目的。另一方面,一个

template<typename T>
void sto(std::string x,T& t);
Run Code Online (Sandbox Code Playgroud)

正如你所意识到的那样会很有用。在 C++17 中有std::from_chars,它或多或少地做到了这一点(它不是模板,而是一组重载,它使用指向字符而不是字符串的指针,但这只是次要细节)。

PS 在上面的表达式中没有简单的方法可以推断出所需的类型,但是有一种方法。我不认为你的问题的核心正是你要求的签名,我不认为以下是实现它的好方法,但我知道有一种方法可以使上述int x = sto("1");编译,我很想看到它在行动。

#include <iostream>
#include <string>

struct converter {
    const std::string& x;
    template <typename T> operator T() { return 0;}
};

template <> converter::operator int() { return stoi(x); }
template <> converter::operator double() { return stod(x); }
converter sto(const std::string& x) { return {x}; }

int main() {
    std::string s{"1.23"};
    int x = sto(s);
    double y = sto(s);
    std::cout << x << " " << y;
}
Run Code Online (Sandbox Code Playgroud)

这按预期工作,但它有严重的缺点,也许最重要的是它允许写入auto x = sto(s);,即很容易使用错误。


Łuk*_*zyk 5

与所有(甚至更旧的 C++ 编译器,如 C++-98 编译器)兼容的解决方案是使用boost::lexical_cast,它是一个以两种方式在数字和字符串类型之间进行转换的模板。

例子:

short myInt = boost::lexical_cast<short>(*argv);
std::string backToString = boost::lexical_cast<std::string>(myInt);
Run Code Online (Sandbox Code Playgroud)

请参阅:https : //www.boost.org/doc/libs/1_42_0/libs/conversion/lexical_cast.htm