提问人:Max Nov 提问时间:8/13/2023 最后编辑:paleonixMax Nov 更新时间:8/14/2023 访问量:59
不明白如何制作istream机械手
Can't understand how to make istream manipulator
问:
我想制作一个从文件中读取二进制文件并写入 .我实现了这个类int32_le_read(x)
x
int32_bin_manip
class bin_manip
{
public:
bin_manip();
~bin_manip();
friend std::istream& operator>>(std::istream& is,bin_manip& obj);
friend std::ostream& operator<<(std::ostream& os, const bin_manip& obj);
virtual std::ostream& write(std::ostream& os) const = 0;
virtual std::istream& read(std::istream& is) = 0;
};
class int32_bin_manip : public bin_manip
{
public:
int32_t* x;
int32_bin_manip(int& x);
std::ostream& write(std::ostream& os) const;
std::istream& read(std::istream& is);
};
对于它和存在。我现在如何为它制作一个操纵器?对于操纵器,我刚刚创建了一个函数,该函数返回此类的实例,一切正常。operator>>
operator<<
istream
ostream
int32_bin_manip write_le_int32(int& x)
{
return int32_bin_manip(x);
}
但是我不能用操纵器这样做,因为它的参数是 ,不像 ,这意味着我不能创建一个返回 的实例的函数并像 一样使用它,因为它会将临时实例绑定到一个被禁止的非常量引用。那么我需要如何实现这样的操纵器呢?istream
int32_bin_manip& obj
const int32_bin_manip& obj
int32_bin_manip
istream >> int32_le_read(x)
答:
3赞
Ted Lyngmo
8/13/2023
#1
你不能将非左值引用绑定到临时引用,但你不必这样做,因为你不是修改对象本身,而是修改它所指向的另一个对象,所以也要接受它:const
operator>>
const&
class bin_manip {
public:
virtual ~bin_manip() = default; // <- added
friend std::istream& operator>>(std::istream& is, const bin_manip& obj);
// ^^^^^ added
friend std::ostream& operator<<(std::ostream& os, const bin_manip& obj);
virtual std::ostream& write(std::ostream& os) const = 0;
virtual std::istream& read(std::istream& is) const = 0;
// ^^^^^ added
};
评论
0赞
Max Nov
8/13/2023
谢谢!我理解这一点,但我认为如果我对 c 样式字符串做同样的事情,这个解决方案将不起作用,因为在这种情况下,我需要为指针重新分配空间。对不起,我当然应该在问题中写下这一点。
0赞
Ted Lyngmo
8/13/2023
@MaxNov嗯,我真的看不出那会是什么样子。也许您也可以将其添加到问题中?
0赞
Max Nov
8/13/2023
我找到了解决这个问题的方法,我认为现在不值得将其添加到原始问题中,但我会解释问题是什么。我想制作类似的操纵器,它必须像这样工作:istream >> read_c_str,其中 s 是 (char*)。在这种情况下,我必须将指向 s 的指针保存在我的操纵器类中,当调用>>运算符时,指针必须擦除,然后以新的长度再次创建(删除 s; s = new char[size_of_string]),因此我无法将读取函数标记为常量。
0赞
Max Nov
8/13/2023
但是我找到了另一种方法,我只是使用 s 作为缓冲区并在 s 的声明中为它分配足够的空间,然后我只是用 istream 中的新字符填充这个字符串,而无需重新分配这个指针@Ted Lyngmo
0赞
fabian
8/13/2023
#2
您可以简单地添加另一个重载,将右值引用为 ;右值引用在函数的函数体中以右值引用为参数,作为对非常量的左值引用。int32_bin_manip
注意:为简洁起见,以下示例中删除了功能,因为在这种情况下使用没有问题。write
const
class bin_manip
{
public:
virtual std::istream& read(std::istream& is) = 0;
friend std::istream& operator>>(std::istream& is, bin_manip& obj)
{
obj.read(is);
return is;
}
};
class int32_bin_manip : public bin_manip
{
int32_t& m_x;
public:
constexpr int32_bin_manip(int32_t& x)
: m_x(x)
{
}
std::istream& read(std::istream& is) override
{
is >> m_x;
return is;
}
friend std::istream& operator>>(std::istream& is, int32_bin_manip&& obj)
{
obj.read(is);
return is;
}
};
int main() {
int32_t i;
std::cin >> int32_bin_manip(i);
std::cout << i << '\n';
}
根据您的设计,您可能希望引入一个具有 2 个独立重载的函数,用于对左值和右值引用的函数调用,如果这更适合您的设计:read
class bin_manip
{
public:
virtual std::istream& read(std::istream& is) & = 0; // this one works just for lvalues, not for rvalue references
friend std::istream& operator>>(std::istream& is, bin_manip& obj)
{
obj.read(is);
return is;
}
};
class rvalue_enabled_bin_manip : public bin_manip
{
public:
using bin_manip::read;
virtual std::istream& read(std::istream& is)&& // overload for rvalues
{
// fall back to standard, non-rvalue
return read(is);
}
friend std::istream& operator>>(std::istream& is, rvalue_enabled_bin_manip&& obj)
{
std::move(obj).read(is);
return is;
}
};
class int32_bin_manip : public rvalue_enabled_bin_manip
{
int32_t& m_x;
public:
constexpr int32_bin_manip(int32_t& x)
: m_x(x)
{
}
std::istream& read(std::istream& is) & override
{
is >> m_x;
return is;
}
};
评论
friend std::istream& operator>>(std::istream& is,bin_manip& obj);
friend std::istream& operator>>(std::istream& is,const bin_manip& obj);
const
const
const_cast
mutable
const