提问人:0xbadf00d 提问时间:10/29/2023 更新时间:10/30/2023 访问量:174
与“std::stof”相比,编写一个没有开销的通用“string_to_float<T>”
Writing a generic `string_to_float<T>` without overhead compared to `std::stof`
问:
我想编写一个带有模板参数的函数,分别是 、 和 、 、 和 。我的尝试如下:string_to_float
T
string_to_float = std::stof
string_to_float = std::stod
string_to_float = std::stold
T = float
T = double
T = long double
template<typename T>
T string_to_float(std::string const& s, std::size_t* pos = nullptr)
{
static_assert(std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, long double>,
"T is not a built-in floating point type");
if constexpr (std::is_same_v<T, float>)
return std::stof(s, pos);
if constexpr (std::is_same_v<T, double>)
return std::stod(s, pos);
if constexpr (std::is_same_v<T, long double>)
return std::stold(s, pos);
return T{};
}
但是,我担心这个声明。虽然在这种情况下静态断言已经失败,但我不想在默认不可构造时产生额外的误导性编译器错误。return
T
我还想确保调用 的代码确实与我使用 、 或直接使用的代码完全相同(当然,假设 ,或者 )。string_to_float
std::stof
std::stod
std::stold
T = float
T = double
T = long double
这就是为什么我没有删除最后一个 if 子句检查是否等于并简单地在最后一行返回的原因。另一方面,在编译时,已经很清楚是否或在这种情况下,最后一行中会有一个 pre the;因此,编译器可能会忽略它。T
long double
std::stold(s, pos);
T = float
T = double
return
return
return
我还查看了属性说明符序列,并希望有某种属性,以便编译器真正知道永远不会到达此行以下的代码。[[unreachable]]
答:
我不想在默认情况下不可构造时产生额外的误导性编译器错误。
T
然后,不要包括最后一个.无论如何,它永远不会被使用。return T{};
例:
template<class T>
inline constexpr bool always_false_v = false;
template <typename T>
T string_to_float(std::string const& s, std::size_t* pos = nullptr) {
if constexpr (std::is_same_v<T, float>)
return std::stof(s, pos);
else if constexpr (std::is_same_v<T, double>)
return std::stod(s, pos);
else if constexpr (std::is_same_v<T, long double>)
return std::stold(s, pos);
else
static_assert(always_false_v<T>,
"T is not a built-in floating point type");
}
根据CWG2518,不实现新规则的旧版本编译器需要变量模板,而不仅仅是变量模板。always_false_v
false
示例(包括版本):
- GCC 高达 12.3
- 最多 16 个
- ICX 至 2023.1.0
- 即使在当前的最新版本中,MSVC 仍然无法处理。
false
评论
always_false_v<T>
false
if constexpr
false
您可以提供 3 个禁止通用模板的专用化,而不是静态断言和类型检查。
#include <string>
template<typename T>
T string_to_float(std::string const & s, std::size_t * pos = nullptr) = delete;
template<>
float string_to_float(std::string const & s, std::size_t * pos)
{
return std::stof(s, pos);
}
template<>
double string_to_float(std::string const & s, std::size_t * pos)
{
return std::stod(s, pos);
}
template<>
long double string_to_float(std::string const & s, std::size_t * pos)
{
return std::stold(s, pos);
}
评论
string_to_float
template<> float string_to_float<float>
stof
stod
stold
template<std::floating_point T> foo() { … string_to_float<T>(s)
float(std::string const&, std::size_t*)
T(std::string const&, std::size_t*)
评论
std::无法到达
出现在C++23中#include <concepts>
template<std::floating_point T>