我试图创建一个从二进制文件读取和写入的类。
我的问题在于我的模板函数,我需要能够读取一个向量,但也检查它是否是一个类,如果它是一个类,我需要调用类读取,否则只读取文件。
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();
}
};
答案 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_class
。 is_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