C++处理wav音频时如何根据采样位宽声明对应类型的同名变量
C++ 多类型同名变量适配方案(音频采样位深场景)
针对不同采样位深对应不同存储类型、且不想维护多份重复业务代码的需求,可参考以下两种主流实现方案:
方案1:泛型函数封装(兼容C++11及以上,最通用)
核心思路是将所有和buffer相关的业务逻辑抽为模板函数,仅维护一份业务代码,不同类型分支直接调用模板即可:
// 泛型业务处理函数,所有buffer相关逻辑只写一次 template <typename SampleType> void process_audio_buffer(SampleType* buffer, size_t sample_count) { // 示例业务逻辑:采样值转浮点数 for (size_t i = 0; i < sample_count; ++i) { float norm_val; if constexpr (std::is_same_v<SampleType, int16_t>) { norm_val = buffer[i] / 32768.0f; } else if constexpr (std::is_same_v<SampleType, uint8_t>) { norm_val = (buffer[i] - 128) / 128.0f; } // 后续处理归一化后的采样值 } } // 主逻辑分支 const size_t sample_count = 1024; if (bytesPerSample == 2) { auto buffer = std::make_unique<int16_t[]>(sample_count); // 填充buffer数据的逻辑... process_audio_buffer(buffer.get(), sample_count); } else if (bytesPerSample == 1) { auto buffer = std::make_unique<uint8_t[]>(sample_count); // 填充buffer数据的逻辑... process_audio_buffer(buffer.get(), sample_count); } else { std::cout << "bytesPerSample: " << bytesPerSample << " is unsupported" << std::endl; }
方案2:std::variant + 访问者模式(C++17及以上,适合buffer需跨分支使用的场景)
如果需要在if分支之外保留buffer的生命周期统一管理,可以用std::variant存储所有可能的类型,后续通过std::visit访问:
#include <variant> // 定义可容纳所有支持的buffer类型的variant using AudioBuffer = std::variant<std::unique_ptr<int16_t[]>, std::unique_ptr<uint8_t[]>>; const size_t sample_count = 1024; AudioBuffer buffer; if (bytesPerSample == 2) { buffer = std::make_unique<int16_t[]>(sample_count); } else if (bytesPerSample == 1) { buffer = std::make_unique<uint8_t[]>(sample_count); } else { std::cout << "bytesPerSample: " << bytesPerSample << " is unsupported" << std::endl; return; } // 任意位置需要处理buffer时调用std::visit即可 std::visit([sample_count](auto&& buf) { using SampleType = typename std::decay_t<decltype(buf)>::element_type; // 这里直接写业务逻辑,和泛型函数内写法完全一致 for (size_t i = 0; i < sample_count; ++i) { float norm_val; if constexpr (std::is_same_v<SampleType, int16_t>) { norm_val = buf[i] / 32768.0f; } else if constexpr (std::is_same_v<SampleType, uint8_t>) { norm_val = (buf[i] - 128) / 128.0f; } } }, buffer);
注意事项
- 不建议使用
void*存储不同类型的指针,会丢失编译期类型检查能力,容易引发类型转换错误、访问越界等未定义行为 - 优先使用智能指针管理堆内存,避免分支提前返回、异常抛出等场景导致的内存泄漏
- 后续新增支持的采样类型(如32位浮点采样)只需新增对应分支、扩展variant可容纳类型即可,原有通用业务逻辑无需修改
内容的提问来源于stack exchange,提问作者WhisperingShiba
相关产品推荐
相关产品推荐

