【问题标题】:Iterate vector inside method在方法内迭代向量
【发布时间】:2015-05-24 19:43:19
【问题描述】:

我目前正在学习 C++,我有以下工作代码:

int main(int argc, char** argv) {
        map<unsigned int, list<mpz_class>> otp;

        // .....

        for(auto it1 = otp.begin(); it1 != otp.end(); ++it1) {
                bool first = true;
                for(auto it2 = it1->second.begin(); it2 != it1->second.end(); ++it2) {
                        if (!first) {
                                cout << ", ";
                        } else {
                                first = false;
                        }
                        cout << *it2;
                }
        }
}

我想把列表的打印放到一个函数中。

这是我的尝试:

void prnt_list(vector it, ostream outstr, string delimiter) {
        bool first = true;
        for(auto it2 = it.begin(); it2 != it.end(); ++it2) {
                if (!first) {
                        outstr << delimiter;
                } else {
                        first = false;
                }
                outstr << *it2;
        }
}

int main(int argc, char** argv) {
    map<unsigned int, list<mpz_class>> otp;

    // .....

    for(auto it1 = otp.begin(); it1 != otp.end(); ++it1) {
        prnt_list(it1->second, cout, ", ");
    }
)

它不编译:

error: variable or field 'prnt_list' declared void
error: missing template arguments before 'it'
error: expected primary-expression before 'outstr'
error: expected primary-expression before 'delimiter'

然后我尝试了这个:

template <typename T>
void prnt_list<T>(vector<T> it, ostream outstr, string delimiter) {
    ...
}

但它也不起作用。

另外,我也不喜欢强制模板,因为我想允许任何向量。如果我能以某种方式使用auto 关键字,那就更舒服了。

【问题讨论】:

  • 尝试ostream&amp; 而不是ostream
  • @VladfromMoscow std::vector 可能。
  • @VladfromMoscow std::vector 。我认为这是我需要得到.begin.end()
  • @milleniumbug C++ 中是否存在从 std::list 到 std::vector 的隐式转换?
  • std::copy(otp.begin(), otp.end(), infix_ostream_iterator(std::cout, ", "));

标签: c++ templates iterator


【解决方案1】:

函数可以通过以下方式定义

std::ostream & prnt_list( const std::list<mpz_class> &lst, 
                          std::ostream &os = std::cout, 
                          const char *delimiter = ", " ) 
{
    bool first = true;

    for ( const auto &obj : lst ) 
    {
        if ( first ) first = false;
        else os << delimiter;

        os << obj;
    }

    return os;
}

并像这样称呼

for ( const auto &p : otp ) prnt_list( p.second ) << std::endl;

您可以为任何容器编写通用函数。例如

template <class Container>
std::ostream & prnt_list( const Container &container, 
                          std::ostream &os = std::cout, 
                          const char *delimiter = ", " ) 
{
    bool first = true;

    for ( const auto &obj : container ) 
    {
        if ( first ) first = false;
        else os << delimiter;

        os << obj;
    }

    return os;
}

至于您的代码,那么至少没有声明标识符向量并且流不可复制。

【讨论】:

  • 非常感谢您提供此解决方案。 const auto &amp;p 似乎是一种非常优雅且简单的迭代方式。在该方法中,我会添加template&lt;typename T&gt; 以使其更加通用。我可以问第二个问题吗?像这样的事情可能std::cerr &lt;&lt; prnt_list(x) &lt;&lt; std::endl 吗? (也许即使没有ostream 参数,因为函数“知道”它的输出将在哪里(在这个例子中是stderr)?
  • @rinntech 您可以调用类似 prnt_list( x, std::cerr ) 的函数
  • 是的,我知道。我只是好奇是否可以在没有这个参数的情况下实现它。当我学习一门编程语言时,我对很多事情感到好奇。我遇到的问题是:std::cout &lt;&lt; "x = {" &lt;&lt; prnt_list(x) &lt;&lt; "}" &lt;&lt; std::endl。这不起作用,所以我必须将其拆分:std::cout &lt;&lt; "x = {"; prnt_list(x) &lt;&lt; "}" &lt;&lt; std::endl
  • @rinntech 拆分语句并不是一个糟糕的解决方案。
  • 为什么用 const char* 作为分隔符?
【解决方案2】:

您正在向需要 vector 的函数发送 list
泛型可能如下所示:

template <typename T>
void prnt_list(const T& it, std::ostream& outstr, const std::string& delimiter)
{
    bool first = true;
    for( auto&& obj : it ) {
        if (!first)
            outstr << delimiter;
        else
            first = false;
        outstr << obj;
    }
}

还要注意&lt;&lt; 必须为mpz_class 定义

它需要标题 &lt;string&gt;&lt;iostream&gt;

【讨论】:

    【解决方案3】:

    问题是:

    map<unsigned int, list<mpz_class>> otp;
    

    有第二个列表,作为 prnt_list 的第一个参数,你有向量。为什么?

    要修复这些错误,请使用以下 prnt_list 签名:

    template<typename T>
    void prnt_list(list<T>& it, ostream& outstr, string delimiter) {
    

    【讨论】:

    • 非常感谢您。我想知道,是否需要为每个具有 begin()end() 的类实现此功能?我是 C++ 新手,我认为向量、映射、列表等是提供开始和结束的通用迭代器类型的某种后代。那么,这没有通用的形式吗?
    • 为了更通用,你没有提到容器类型,所以不要说list&lt;T&gt;&amp;,你只说T&amp;。各种容器没有继承关系,但接口足够相似,您可以将它们与模板一起通用
    • @rinntech 与 sp2danny 评论中的完全一样,如果您使用 begin(it) 而不是 it.begin() (对于 end 也是如此),它也适用于没有 begin 的数组和其他容器/end 方法,但存在全局重载函数 begin/end。我不确定,但如果你使用 auto 那么它是这样实现的。
    【解决方案4】:

    扩展弗拉德的答案 - 允许 print_list 参与 ostream &lt;&lt; 链:

    #include <iostream>
    #include <list>
    
    namespace detail {
    
        // it's called a simple list printer because it assumes that
        // list::value_type is printable
        template<class T, class A>
        struct simple_list_printer {
            simple_list_printer(const std::list<T, A>& list, std::string delimiter)
            : _list { list }
            , _delimiter { delimiter }
            {}
    
            void write(std::ostream& os) const {
                bool first = true;
    
                for ( const auto &obj : _list )
                {
                    if ( first ) first = false;
                    else os << _delimiter;
    
                    os << obj;
                }
            }
        private:
            const std::list<T, A>& _list;
            std::string _delimiter;
        };
    
        // stream an simple_list_printer to any ostream
        template<class T, class A>
        inline std::ostream& operator<<(std::ostream& os, const simple_list_printer<T, A>& slp)
        {
            slp.write(os);
            return os;
        }
    }
    
    // a mockup of mpz_class
    struct mpz_class {
    
        void write(std::ostream& os) const {
            os << "{ i am an mpz - write my members here }";
        }
    };
    
    // stream an mpz to any ostream
    inline std::ostream& operator<<(std::ostream& os, const mpz_class& mpz)
    {
        mpz.write(os);
        return os;
    }
    
    // construct a simple_list_printer
    template<class A>
    detail::simple_list_printer<mpz_class, A>
    print_list(const std::list<mpz_class, A>& list, std::string delimiter = std::string { ", " })
    {
        return { list, std::move(delimiter) };
    }
    
    int main()
    {
        std::list<mpz_class> a { {}, {} };
    
        std::cout << print_list(a) << std::endl;
        std::cerr << print_list(a) << std::endl;
        std::clog << print_list(a) << std::endl;
    
        std::cout << print_list(a, "\n") << std::endl;
        std::cout << std::endl;
        std::cerr << print_list(a, " * ") << std::endl;
        std::clog << print_list(a, " <--> ") << std::endl;
    
        return 0;
    }
    

    预期输出:

    { i am an mpz - write my members here }, { i am an mpz - write my members here }
    { i am an mpz - write my members here }, { i am an mpz - write my members here }
    { i am an mpz - write my members here }, { i am an mpz - write my members here }
    { i am an mpz - write my members here }
    { i am an mpz - write my members here }
    
    { i am an mpz - write my members here } * { i am an mpz - write my members here }
    { i am an mpz - write my members here } <--> { i am an mpz - write my members here }
    

    【讨论】:

      猜你喜欢
      • 2021-12-20
      • 2015-06-16
      • 2015-05-24
      • 2013-07-16
      • 2017-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多