【问题标题】:Declare variable with unknown type声明类型未知的变量
【发布时间】:2014-04-08 18:58:52
【问题描述】:

我正在用 c++ 程序读取 .wav 文件。

.wav 格式的样本是uint8_tint16_t。是否可以根据具体文件的格式来声明变量?

一种解决方案是:

int16_t sample;
if (bits==8)
{
  uint8_t temp8;
  in.read((char*)&temp8,bits);
  sample = (int16_t) temp8;
}
else
{
  in.read((char*)&sample,bits);
}

从现在开始我可以使用sample。然而,这似乎不是很方便,在 8 位的情况下,变量 sample 比它所需要的要大。

我相信这也可以通过联合来完成,但无论如何它仍然会使变量占用 2 个字节。

我真正想要的是:

if(bits==8)
  uint8_t sample;
else
  int16_t sample;

但范围超出了条件语句。

【问题讨论】:

  • 您可以将其设为模板函数
  • @dutt 模板在编译时被解析,所以绝对不会。
  • 如果你是老派,请使用 void 指针
  • 您的原始解决方案对我来说似乎是最好的
  • @remudada void 指针似乎提供了一个有趣的解决方案,但指针算术和数组似乎相当有限,不是吗?

标签: c++


【解决方案1】:

您可以使用抽象基类和模板类来提供示例阅读器的不同实现。使用抽象接口,后面的代码不需要知道它是处理 8 位还是 16 位样本。

#include <fstream>
#include <vector>
#include <exception>

class SampleReader
{
public:
    virtual void readSample( std::ifstream &in ) = 0;
};

template<class T>
class SampleReaderT : public SampleReader
{
public:
    virtual void readSample( std::ifstream &in )
    {
        while (!in.eof()) {
            const T value = readOneValue(in);
            if (in) {
                _sample.push_back();
            } else {
                break;
            }
        }
    }

private:
    T readOneValue( std::ifstream &in )
    {
        T inputUnit;
        in.read((char*)&inputUnit,sizeof(T));
    }

private:
    std::vector<T> _sample;
};

typedef SampleReaderT<int8_t> SampleReader8Bit;
typedef SampleReaderT<int16_t> SampleReader16Bit;

int main(int argc, char** argv)
{
    int sampleBits = 8;

    SampleReader *sampleReader = nullptr;
    if (sampleBits == 8) {
        sampleReader = new SampleReader8Bit();
    } else if (sampleBits == 16) {
        sampleReader = new SampleReader16Bit();
    } else {
        throw std::out_of_range("unknown bit number");
    }

    std::ifstream in("test.dat");
    sampleReader->readSample(in);
}

请注意此示例中的以下内容:

  • 这只是一个示例,您当然需要为您的项目找到更好的设计。
  • 有一个带有纯虚方法的基类。这个基类对你的代码抽象很有帮助。您只需使用指向 SampleReader 的指针即可,不必知道这是 8 位还是 16 位示例阅读器。
  • 显示的读取值的方式与平台无关。有些平台的字节顺序不同。
  • 此示例中缺少错误处理。读取流随时可能引发错误。

【讨论】:

  • while(!eof) 成语最后会推入一个垃圾字符;相反,您需要测试读取操作。而readOneValue 需要return 声明。 (我意识到这只是一个草率的例子,但如果 OP 复制你的代码,他可能会忽略这些事情)
  • 感谢您的贡献!如果您要根据 Matt 更正示例,您可能还需要更正 uint16_t - 16bit wav 样本不是无符号的。如果没有人提供更短更优雅的解决方案,我会接受这一点。
  • @MattMcNabb 你是绝对正确的。我在示例中为此案例添加了一个测试。显示的代码应始终尽可能地具有示范性。
  • @Juris 我将类型更改为已签名的类型。请注意,这只是一个示例,您应该花一些时间进行良好的设计。这里的基本原则是使用接口隐藏实现细节
  • @Juris 如果您使用这样的实现编写抽象代码,则可以使用可以从文件中读取的每种类型。您还可以添加一个读取浮点值的版本。如果格式不匹配,只需编写重新实现的专用子类,例如readOneValue 方法(使其受保护,虚拟优先)。
猜你喜欢
  • 1970-01-01
  • 2018-03-07
  • 1970-01-01
  • 2019-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多