现代C++中void指针的替代方案:实现类型安全的数据获取
用现代C++重构无void指针的类型安全数据获取方案
你原来的C风格实现依赖void指针传递目标变量,虽然能工作,但丢失了类型安全——编译器无法帮你检查指针转换的正确性,容易埋下bug。下面是几种现代C++的重构方式,彻底解决这个问题:
方案1:基于引用的类型安全转换函数
保留原有的“将数据写入目标变量”的语义,把转换函数的void*参数替换成目标类型的引用,再通过模板让getData自动推导类型:
#include <iostream> // 转换函数直接接收目标类型的引用,无需void* void getInt(int& dest, const double& src) { dest = static_cast<int>(src); } void getDouble(double& dest, const double& src) { dest = src; } struct twoInt{int a; int b;}; void getTwoInt(twoInt& dest, const double& src) { dest.a = static_cast<int>(src); dest.b = static_cast<int>(src * 10) % 10; } // getData模板根据目标类型推导转换函数的签名 template<typename T> void getData(void(*converter)(T&, const double&), T& dest) { double dataSource = 2.1; converter(dest, dataSource); } int main() { int valI; double valD; twoInt valTwoInt; // 直接传递变量,无需任何类型转换 getData(getInt, valI); std::cout << "Int: " << valI << std::endl; getData(getDouble, valD); std::cout << "Double: " << valD << std::endl; getData(getTwoInt, valTwoInt); std::cout << "Int1: " << valTwoInt.a << ", Int2: " << valTwoInt.b << std::endl; }
这种方式完全保留了你原有的代码逻辑,但所有类型检查都在编译期完成,再也不会出现void指针转换错误的问题。
方案2:返回值式转换(更简洁的现代风格)
如果不需要预先定义目标变量,可以让转换函数直接返回目标类型,getData调用转换函数后返回结果,代码更简洁:
#include <iostream> // 转换函数直接返回目标类型 int getInt(const double& src) { return static_cast<int>(src); } double getDouble(const double& src) { return src; } struct twoInt{int a; int b;}; twoInt getTwoInt(const double& src) { return {static_cast<int>(src), static_cast<int>(src * 10) % 10}; } // getData自动推导返回类型,无需显式指定 template<typename Converter> auto getData(Converter converter) { double dataSource = 2.1; return converter(dataSource); } int main() { // 直接接收返回值,变量定义和初始化一步完成 int valI = getData(getInt); double valD = getData(getDouble); twoInt valTwoInt = getData(getTwoInt); std::cout << "Int: " << valI << std::endl; std::cout << "Double: " << valD << std::endl; std::cout << "Int1: " << valTwoInt.a << ", Int2: " << valTwoInt.b << std::endl; }
这种方式符合现代C++的“值语义”风格,代码更紧凑,同时依然保持完全的类型安全。
方案3:用仿函数/λ表达式扩展灵活性
如果需要更灵活的转换逻辑(比如带状态的转换),可以用仿函数或者λ表达式替代普通函数:
#include <iostream> struct twoInt{int a; int b;}; // 带参数的仿函数示例 struct ScaleIntConverter { int scale; explicit ScaleIntConverter(int s) : scale(s) {} void operator()(int& dest, const double& src) { dest = static_cast<int>(src * scale); } }; template<typename T, typename Converter> void getData(Converter converter, T& dest) { double dataSource = 2.1; converter(dest, dataSource); } int main() { int scaledVal; twoInt valTwoInt; // 使用λ表达式作为转换函数 getData([](twoInt& dest, const double& src) { dest.a = static_cast<int>(src); dest.b = static_cast<int>(src * 100) % 100; }, valTwoInt); std::cout << "Int1: " << valTwoInt.a << ", Int2: " << valTwoInt.b << std::endl; // 使用带状态的仿函数 getData(ScaleIntConverter(5), scaledVal); std::cout << "Scaled Int: " << scaledVal << std::endl; }
这种方式适合复杂的转换场景,同时依然保持类型安全。
内容的提问来源于stack exchange,提问作者manuel
相关产品推荐
相关产品推荐

