You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

现代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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 08:27:34