如何键入用于 const 对象的自定义 io 操纵器?
How to type custom io manipulators for use with const objects?
我正在尝试提升我为使用 std::vector
s 而编写的简单 Array-io 操纵器。这是我一直在使用的旧签名:
template<typename T>
struct arr {
const size_t size;
T* values;
arr(const size_t size, T* values) : size(size), values(values) {};
friend std::ostream& operator<<(std::ostream& os, const arr<T>& array);
friend std::istream& operator>>(std::istream& is, arr<T>& array);
};
现在我试着像这样提起它:
template<typename T>
struct arr {
std::vector<T>& vec;
arr(std::vector<T>& vec) : vec(vec) {};
friend std::ostream& operator<<(std::ostream& os, const arr<T>& array);
friend std::istream& operator>>(std::istream& is, arr<T>& array);
};
但是我面临以下问题:我想在 const
声明的成员方法中使用 << arr(member)
。这当然不能编译:
error: binding reference of type ‘std::vector<std::unique_ptr<IController> >&’ to ‘const std::vector<std::unique_ptr<IController> >’ discards qualifiers
然而,当我将构造函数参数和 arr::vec
更改为 const std::vector<T>&
时,我遇到了相反的问题,>> arr(member)
无法再工作了!
我希望通过将 arr
实例初始化为 const
我可以解决这个问题,但我遇到了同样的编译器错误,下面一行:
const streamutils::arr<int> list(myVector);
如何在不为进出方向声明两种不同类型的情况下解决这个问题?
我试图查看 libstdc++ 源代码以了解它是如何为 std::quoted
完成的,但我无法弄清楚。
您可以不使用 T
而是使用 vector<T>
本身对操纵器进行参数化。这样你就不用担心你的向量是不是 const 了。同时创建一个辅助函数,它 returns 具有相应模板类型的 class 实例。
template<typename T>
using is_vector = std::is_same<T, std::vector<typename T::value_type, typename T::allocator_type>>;
template<typename T>
struct Arr {
static_assert(is_vector<std::decay_t<T>>::value);
T& vec;
// Note that arr is passed by value here because it is a temporary
// in expressions like 'cin >> arr(a)'
template<typename U>
friend std::enable_if_t<!std::is_const_v<U>, std::istream&> operator>>(std::istream& in, Arr<U> Arr);
template<typename U>
friend std::ostream& operator<<(std::ostream& out, const Arr<U>& Arr);
};
template<typename T>
std::enable_if_t<!std::is_const_v<T>, std::istream&> operator>>(std::istream& in, Arr<T> arr) {
int n;
in >> n;
arr.vec.resize(n);
for (int i = 0; i < n; ++i) {
in >> arr.vec[i];
}
return in;
}
template<typename T>
std::ostream& operator<<(std::ostream& out, const Arr<T>& arr) {
out << arr.vec.size() << "\n";
for (const auto& x: arr.vec) {
out << x << " ";
}
out << "\n";
return out;
}
template<typename T, typename = typename is_vector<std::decay_t<T>>::type>
Arr<T> arr(T& t)
{
return Arr<T>{t};
}
int main() {
vector<int> a;
cin >> arr(a);
cout << arr(a) << endl;
const vector<int> b{1, 2, 3};
cin >> arr(b); // compile error
cout << arr(b) << endl;
}
此外,请考虑阅读 this post,它解释了交友模板运算符的各种方法(我在这里展示的不是最好的,也不是唯一可能的)。
我正在尝试提升我为使用 std::vector
s 而编写的简单 Array-io 操纵器。这是我一直在使用的旧签名:
template<typename T>
struct arr {
const size_t size;
T* values;
arr(const size_t size, T* values) : size(size), values(values) {};
friend std::ostream& operator<<(std::ostream& os, const arr<T>& array);
friend std::istream& operator>>(std::istream& is, arr<T>& array);
};
现在我试着像这样提起它:
template<typename T>
struct arr {
std::vector<T>& vec;
arr(std::vector<T>& vec) : vec(vec) {};
friend std::ostream& operator<<(std::ostream& os, const arr<T>& array);
friend std::istream& operator>>(std::istream& is, arr<T>& array);
};
但是我面临以下问题:我想在 const
声明的成员方法中使用 << arr(member)
。这当然不能编译:
error: binding reference of type ‘std::vector<std::unique_ptr<IController> >&’ to ‘const std::vector<std::unique_ptr<IController> >’ discards qualifiers
然而,当我将构造函数参数和 arr::vec
更改为 const std::vector<T>&
时,我遇到了相反的问题,>> arr(member)
无法再工作了!
我希望通过将 arr
实例初始化为 const
我可以解决这个问题,但我遇到了同样的编译器错误,下面一行:
const streamutils::arr<int> list(myVector);
如何在不为进出方向声明两种不同类型的情况下解决这个问题?
我试图查看 libstdc++ 源代码以了解它是如何为 std::quoted
完成的,但我无法弄清楚。
您可以不使用 T
而是使用 vector<T>
本身对操纵器进行参数化。这样你就不用担心你的向量是不是 const 了。同时创建一个辅助函数,它 returns 具有相应模板类型的 class 实例。
template<typename T>
using is_vector = std::is_same<T, std::vector<typename T::value_type, typename T::allocator_type>>;
template<typename T>
struct Arr {
static_assert(is_vector<std::decay_t<T>>::value);
T& vec;
// Note that arr is passed by value here because it is a temporary
// in expressions like 'cin >> arr(a)'
template<typename U>
friend std::enable_if_t<!std::is_const_v<U>, std::istream&> operator>>(std::istream& in, Arr<U> Arr);
template<typename U>
friend std::ostream& operator<<(std::ostream& out, const Arr<U>& Arr);
};
template<typename T>
std::enable_if_t<!std::is_const_v<T>, std::istream&> operator>>(std::istream& in, Arr<T> arr) {
int n;
in >> n;
arr.vec.resize(n);
for (int i = 0; i < n; ++i) {
in >> arr.vec[i];
}
return in;
}
template<typename T>
std::ostream& operator<<(std::ostream& out, const Arr<T>& arr) {
out << arr.vec.size() << "\n";
for (const auto& x: arr.vec) {
out << x << " ";
}
out << "\n";
return out;
}
template<typename T, typename = typename is_vector<std::decay_t<T>>::type>
Arr<T> arr(T& t)
{
return Arr<T>{t};
}
int main() {
vector<int> a;
cin >> arr(a);
cout << arr(a) << endl;
const vector<int> b{1, 2, 3};
cin >> arr(b); // compile error
cout << arr(b) << endl;
}
此外,请考虑阅读 this post,它解释了交友模板运算符的各种方法(我在这里展示的不是最好的,也不是唯一可能的)。