C++-std::to_string内部实现的理解

本文介绍了C++中自定义的非原生to_string函数实现,包括无符号整数和有符号整数的转换方法。重点在于使用static_assert进行编译期错误检查,以及利用逆序转换数字到字符来提高效率。代码示例展示了在不同平台和数据大小下的处理策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、学到的知识

  1. 了解了 to_string 函数的标准库实现
  2. 复习了 #ifdef #else #endif 的使用
  3. 复习了 sizeof 关键字
  4. static_assert 用于编译期报错,语法为:static_assert(常量表达式,提示字符串),表达式为 false,则报错
  5. 编写转换代码时,逆序将数字转换为字符的方法:*--String = '0' + Number%10,地址从高位到低位,数据从地位到高位,妙极了。
    之前的想法是将顺序转换,然后进行反转字符串的操作,相比之下,效率无疑大大降低。

二、代码

非原生 to_string 代码,自行修改了变量名,函数名,类型名,使其更容易理解。

/** Copyright Moota, Private. All Rights Reserved. */

#pragma once
#include "../../Base/Object.h"
#include "../../Container/String/String.h"

class FFormat : public UObject
{
private:
	/** 无符号数值转字符 */
	template <class ResultType, class ValueType>
	static ResultType* UnsignedIntegralToBuff(ResultType* Result, ValueType Value)
	{
		// 进行类型判断
		static_assert(std::is_unsigned_v<ValueType>, "ValueType must be unsigned");
		// 编译在 Win64
		#ifdef _WIN64
		auto Temp = Value;
		#else
		// 编译不在 Win64
		// 判断是否超过了4个字节,超过了就需要特殊处理
		// 为什么不选择8个字节呢,明明 unsigned long long 也可以处理
		// 当然是折中啦
		constexpr bool IsBigType = sizeof(ValueType) > 4;
		if constexpr (IsBigType) {
			// 数值大于 unsigned long 就一直处理
			while (Value > 0xFFFFFFFFU) {
				// 取余再除,经典取低位数据的操作
				auto Temp = static_cast<unsigned long>(Value % 1000000000);
				Value /= 1000000000;
				// 因为 % 10 0000 0000,有9位,所以,一次处理9位
				for (int Index = 0; Index != 9; ++Index) {
					// 逆序将数字变成字符,地址从高位到低位,数据从低位到高位,很巧妙的写法
					*--Result = static_cast<ReturnType>('0' + Temp % 10);
					Temp /= 10;
				}
			}
			// 结束 while 循环时,此时 Value 值小于 unsigned long,>= (0xFFFFFFFFU = 4294967295 / 1000000000) = 4
			// 所以在下面的 do-while 循环时,不需要担心 Value 为0还需要执行一次的情况
		}
		auto Temp = static_cast<unsigned long>(Value);
		#endif

		// do-while循环,先做一次,包含 0 的情况
		do
		{
			*--Result = static_cast<ResultType>('0' + Temp % 10);
			Temp /= 10;
		}
		while (Temp != 0);
		// 返回字符首地址
		return Result;
	}

	/** 处理有符号整数 */
	template <class ResultType, class ValueType>
	static std::basic_string<ResultType> IntegralToString(const ValueType Value)
	{
		static_assert(std::is_integral_v<ValueType>, "ValueType must be integral");

		// 2^64 有20位,使用这个是因为,它属于 unsigned long long的极限值,也是目前支持的最大的整数类型,这样所有的数据尺寸都包含了
		ResultType Buff[21];
		ResultType* const BuffEnd = _STD end(Buff);
		ResultType* BuffStart = BuffEnd;
		const auto UValue = static_cast<std::make_unsigned_t<ValueType>>(Value);

		if (Value < 0)
		{
			// 小于0,0-Value就变成了正数
			BuffStart = UnsignedIntegralToBuff(BuffStart, 0 - UValue);
			// 然后前面添加符号-即可
			*--BuffStart = '-';
		}
		else
		{
			BuffStart = UnsignedIntegralToBuff(BuffStart, UValue);
		}

		return std::basic_string<ResultType>(BuffStart, BuffEnd);
	}

	/** 处理无符号整数 */
	template <class ResultType, class ValueType>
	static std::basic_string<ResultType> UnsignedIntegralToString(const ValueType Value)
	{
		static_assert(std::is_integral_v<ValueType>, "ValueType must be integral");
		static_assert(std::is_unsigned_v<ValueType>, "ValueType must be unsigned");

		// 2^64 有20位
		ResultType Buff[21];
		ResultType* const BuffEnd = std::end(Buff);

		// 非负数就不需要处理符号-的情况
		ResultType* const BuffStart = UnsignedIntegralToBuff(BuffEnd, Value);
		return std::basic_string<ResultType>(BuffStart, BuffEnd);
	}

public:
	// 其他转FString
	static FString ToString(int Content)
	{
		return IntegralToString<char>(Content);
	}

	static FString ToString(unsigned long long Content)
	{
		return UnsignedIntegralToString<char>(Content);
	}

public:
	// FString转其他
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值