`ocutor<<`在容器上适用于价值和参考

发布于 2025-01-24 14:26:45 字数 1726 浏览 2 评论 0原文

有一个模板的容器类容器,因此可以包含任何内容。

我想增加将其内容打印到std :: Ostream的能力,因此我已经Overriden 操作员<<

但是,这有一个缺点:如果容器包含引用(或指针),则该方法仅打印地址而不是真实信息。

请考虑此简单的测试代码,该代码证明了问题:

#include <iostream>
#include <deque>

template<typename T, bool is_reference = false>
class container {
public:
    container() {}
    void add(T a) { queue.push_back(a); }
    
    friend std::ostream& operator<<(std::ostream& out, const container<T, is_reference>& c) {
        for (const T& item : c.queue) {
            if (is_reference) out << *item; else out << item;
            out << ",";
        }
        return out;
    }
    
private:
std::deque<T> queue;
};


int main() {
    //Containers
    container<int*, true> myContainer1;
    container<int> myContainer2;
    
    int myA1(1);
    int myA2(10);
    
    myContainer1.add(&myA1);
    myContainer1.add(&myA2);
    
    myContainer2.add(myA1);
    myContainer2.add(myA2);
    
    std::cout << myA1 << std::endl;
    std::cout << myA2 << std::endl;
    
    std::cout << myContainer1 << std::endl;
    std::cout << myContainer2 << std::endl;
    
    return 0;
}

我有一个想法在模板中提供额外的is_Reference布尔值,以调整ocerator&lt;&lt;&lt;

但是,如果我具有 value type 容器,这会导致早期编译器错误。

我该如何完成这项工作?

如果我将打印机行更改为

out << item << ",";

“代码”编译并打印以下内容:

1
10
0x7ffd77357a90,0x7ffd77357a94,
1,10,

显然我的目标是获得此结果:

1
10
1,10,
1,10,

((如何)我可以轻松实现此目标?

There is a container class container which is templated, so it can contain anything.

I want to add ability to print its contents to std::ostream so I've overriden operator<<.

However this has a drawback: if the container contains references (or pointers), the method only prints addresses instead of real information.

Please consider this simple test code which demonstrates the problem:

#include <iostream>
#include <deque>

template<typename T, bool is_reference = false>
class container {
public:
    container() {}
    void add(T a) { queue.push_back(a); }
    
    friend std::ostream& operator<<(std::ostream& out, const container<T, is_reference>& c) {
        for (const T& item : c.queue) {
            if (is_reference) out << *item; else out << item;
            out << ",";
        }
        return out;
    }
    
private:
std::deque<T> queue;
};


int main() {
    //Containers
    container<int*, true> myContainer1;
    container<int> myContainer2;
    
    int myA1(1);
    int myA2(10);
    
    myContainer1.add(&myA1);
    myContainer1.add(&myA2);
    
    myContainer2.add(myA1);
    myContainer2.add(myA2);
    
    std::cout << myA1 << std::endl;
    std::cout << myA2 << std::endl;
    
    std::cout << myContainer1 << std::endl;
    std::cout << myContainer2 << std::endl;
    
    return 0;
}

I had an idea to provide an extra is_reference boolean in the template for adjusting the operator<<.

However this causes an early compiler error, in case I have value type container(s).

How can I make this work?

If I change the printer line to

out << item << ",";

The code compiles and prints this:

1
10
0x7ffd77357a90,0x7ffd77357a94,
1,10,

Obviously my goal is to have this result:

1
10
1,10,
1,10,

(How) can I achieve this easily?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

倥絔 2025-01-31 14:26:46

您可以使用Sfinae根据std :: is_pointer&lt; t&gt; :: value is true 或false。这已经与C ++ 11:

#include <iostream>
#include <deque>

template<typename T>
class container {
public:
    // container() {} // dont define empty constructor when not needed
    //                   or declare it as = default
    void add(const T& a) { queue.push_back(a); } // should take const&
    
    template <typename U = T, typename std::enable_if< std::is_pointer<U>::value,bool>::type=true> 
    friend std::ostream& operator<<(std::ostream& out, const container<T>& c) {
        std::cout << "is pointer\n";
    }
    template <typename U = T, typename std::enable_if< ! std::is_pointer<U>::value,bool>::type=true>
    friend std::ostream& operator<<(std::ostream& out, const container<T>& c) {
        std::cout << "is not pointer\n";
    }
    
private:
    std::deque<T> queue;
};


int main() {
    //Containers
    container<int*> myContainer1;
    container<int> myContainer2;
    std::cout << myContainer1 << std::endl;
    std::cout << myContainer2 << std::endl;
}

output

is pointer

is not pointer

由于C ++ 17您可以使用> > constexpr如果。另外,由于C ++ 17有std :: IS_POInter_V,并且由于C ++ 14有std :: Enable_if_t,因此两者都会使代码少一些。

You can use SFINAE to select an overload based on whether std::is_pointer<T>::value is true or false. This works already with C++11:

#include <iostream>
#include <deque>

template<typename T>
class container {
public:
    // container() {} // dont define empty constructor when not needed
    //                   or declare it as = default
    void add(const T& a) { queue.push_back(a); } // should take const&
    
    template <typename U = T, typename std::enable_if< std::is_pointer<U>::value,bool>::type=true> 
    friend std::ostream& operator<<(std::ostream& out, const container<T>& c) {
        std::cout << "is pointer\n";
    }
    template <typename U = T, typename std::enable_if< ! std::is_pointer<U>::value,bool>::type=true>
    friend std::ostream& operator<<(std::ostream& out, const container<T>& c) {
        std::cout << "is not pointer\n";
    }
    
private:
    std::deque<T> queue;
};


int main() {
    //Containers
    container<int*> myContainer1;
    container<int> myContainer2;
    std::cout << myContainer1 << std::endl;
    std::cout << myContainer2 << std::endl;
}

Output:

is pointer

is not pointer

Since C++17 you can use constexpr if. Also since C++17 there is std::is_pointer_v and since C++14 there is std::enable_if_t, both would make the code a little less verbose.

娇纵 2025-01-31 14:26:46

对于item*item工作的条件选择,您将需要一个支持C ++ 17标准(或更高版本)的编译器,然后使用>如果constexpr(...)语句。

另外,您可以使用 std :: is_pointer 检查包含的类型是否是指针,而不是在模板中添加“标志”:

#include <iostream>
#include <deque>
#include <type_traits>

template<typename T>
class container {
public:
    container() {}
    void add(T a) { queue.push_back(a); }

    friend std::ostream& operator<<(std::ostream& out, const container<T>& c) {
        for (const T& item : c.queue) {
            if constexpr (std::is_pointer<T>::value) {
                out << *item;
            }
            else {
                out << item;
            }
            out << ",";
        }
        return out;
    }

private:
    std::deque<T> queue;
};

For the conditional choice between item and *item to work, you will need a compiler that supports the C++17 Standard (or later) and then use an if constexpr (...) statement.

Also, you can use std::is_pointer to check whether the contained type is a pointer, rather than adding a 'flag' to your template:

#include <iostream>
#include <deque>
#include <type_traits>

template<typename T>
class container {
public:
    container() {}
    void add(T a) { queue.push_back(a); }

    friend std::ostream& operator<<(std::ostream& out, const container<T>& c) {
        for (const T& item : c.queue) {
            if constexpr (std::is_pointer<T>::value) {
                out << *item;
            }
            else {
                out << item;
            }
            out << ",";
        }
        return out;
    }

private:
    std::deque<T> queue;
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文