如何键入用于const对象的自定义io机械手?

时间:2018-07-23 11:33:03

标签: c++ const iomanip

我正在尝试解除编写的简单Array-io机械手,以使用std::vector s。这是我一直在使用的旧签名:

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);
};

但是,我遇到以下问题:我想从<< arr(member)声明的成员方法内部使用const。当然,这不会编译:

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完成此操作,但是我无法弄清楚。

1 个答案:

答案 0 :(得分:1)

您可以使用T本身而不是vector<T>来参数化机械手。这样,您将不必担心向量是否为const。还创建一个辅助函数,该函数返回具有相应模板类型的类的实例。

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帖子,它介绍了结交朋友模板运算符的各种方法(我在这里展示的方法不是最好的,也不是唯一的可能)。