阅读矢量二进制文件

时间:2018-04-03 04:54:07

标签: c++

我试图创建一个从二进制文件读取和写入的类。

我的问题在于我的模板函数,我需要能够读取一个向量,但也检查它是否是一个类,如果它是一个类,我需要调用类读取,否则只读取文件。

template <class T>
void VecRead(istream& in, T& vector)
{
    size_t size = 0;
    in.read((char*)&size, sizeof(size));
    vector.resize(size);

    for (auto &element : vector)
    {
        // need to check if its a class here
        if (Check_If_T_Is_Class_Type)
            element.read(in);
        else
            in.read((char*)&element, sizeof(T));
    }
}

class Student
{
public:
    string name;
    int age;
    vector<int> grades;
    void read(istream& in)
    {
        readString(in, name);
        in.read((char*)&age, sizeof(int));
        VecRead(in, grades);
    }
};

class File
{
public:
    Header header;
    vector<Student> students;
    void read(const char* fileName)
    {
        std::ifstream in(fileName, std::ios::in | std::ios::binary);
        header.read(in);
        VecRead(in, students);
        in.close();
    }
};

3 个答案:

答案 0 :(得分:1)

根据您要执行的操作,我建议您检查T是否具有正确的方法read,而不仅仅是检查它是否是一个类。

为了进行此检查,您可以创建一个类来检查T是否具有任何类型的read方法,然后检查它的签名。这可以通过以下代码完成:

template<class CC>
class HasReadFunc
{
    template <class C>
    static constexpr bool test_( decltype(&C::read) )
    {
        return std::is_same<
                   decltype(&C::read),
                   void(C::*)(istream&)
                >::value;
    }
    template <class C>
    static constexpr bool test_(...) { return false; }
public:
    static constexpr const bool value = test_<CC>(nullptr);
};

第一次检查是使用SFINAE,第二次检查 - 只需std::is_same

这个类可以像:

一样使用
if( HasReadFunc<T>::value ) ...

这适用于基本类型。

答案 1 :(得分:0)

使用std::is_classis_class<T>::value检查T是否为类类型。如果是,则值为true

但是,无论你使用什么,如果只填写if条件,你就无法成功编译代码。

是的,std::is_class<T>::value是一个文字。它可以在complie时检查。但是,if statement不能包括if constexpr他们无法避免编译器对if语句中的语句进行编译。

因此,我能想到解决这个问题的唯一方法是定义两个函数。一个是类型参数版本。另一种是非类型的。

答案 2 :(得分:0)

不要试图消除函数内部的参数歧义,而是考虑使用重载函数让编译器为您完成工作:

void readElement(istream& in, Student& target)
{
    target.read(in);
}

void readElement(istream& in, int target)
{
    in.read((char*)&target, sizeof(int));
}


template <class T>
void VecRead(istream& in, T& vector)
{
    size_t size = 0;
    in.read((char*)&size, sizeof(size));
    vector.resize(size);

    for (auto &element : vector)
    {
        readElement(in, element);
    }
}

以上只处理提出的两个案例(如果这些是唯一的案例,我建议不要打破模板)。但是,如果您希望这可以使用多种类型,那么模板专业化+ SFINAE就是您的选择:

#include <type_traits>

template <class T>
std::enable_if_t<std::is_trivial_v<T>> readElement(istream& in, T& target)
{
    in.read((char*)&target, sizeof(T));
}

template <class T>
void readElement(istream& in, T& target)
{
    target.read(in);
}

直接读入普通类型,并在其他所有内容上调用.read()。当目标类型不重要且没有read()方法时,您将收到编译时错误,这很好,因为在这种情况下预期的行为不明确。

PS:如果您希望vector的{​​{1}}参数始终是一个向量,那么您应该明确说明:

VecRead