使用std :: for_each进行树遍历

时间:2017-11-29 12:51:20

标签: c++ templates stl

我很擅长在C ++中使用algorithmfunctional。我需要进行树遍历并为每个元素执行一个函数。请参阅下面的代码。

这样可行,但是我有一些我不喜欢的东西,或许可以做得更好。请注意,我仅限于相当旧版本的g ++(4.4.7),不能使用lambda函数。

  1. 我使用包装函数do_walkstd::bind来调用每个元素上的成员函数walk。有没有办法避免包装函数并直接调用成员函数?

  2. 我使用typedef作为回调函数UnaryFunction。我更喜欢使用walk的模板版本。但是,当我更改代码以使用模板时,我得到以下编译错误:error: no matching function for call to 'bind(<unresolved overloaded function type>, std::_Placeholder<1>&, void (*&)(const Elem&))'。是否可以在此上下文中使用模板?

  3. 也许有std::for_each的替代品更适合这种树遍历?

  4. 到目前为止我的代码:

    #include <list>
    #include <algorithm>
    #include <functional>
    
    struct Elem;
    typedef void (*UnaryFunction)(const Elem&); // (2)
    
    struct Elem
    {
        std::list<Elem> children; // Some container, std::list for now.
    
        //template< class UnaryFunction > // (2)
        void walk(UnaryFunction f) const
        {
            // Walk all children.
            std::for_each(
                children.begin(),
                children.end(),
                std::bind(do_walk, std::placeholders::_1, f)); // (1)
    
            // Walk this object.
            f(*this);
        }
    
        //template< class UnaryFunction > // (2)
        static void do_walk(const Elem& elem, UnaryFunction f) // (1)
        {
            elem.walk(f);
        }
    };
    
    void pretty_print(const Elem& elem)
    {
        // Pretty print element.
    }
    
    int main()
    {
        Elem root;
        // Create tree somehow.
        root.walk(pretty_print);
        return 0;
    }
    

2 个答案:

答案 0 :(得分:6)

  1. <style> paper-input {padding-left:10px } </style> <div class="card"> <iron-form id="form3"> <form action="" method="get"> <paper-item> <paper-input float-label label="First Name"></paper-input> <paper-input float-label label="Last Name"></paper-input> </paper-item> <paper-item> <paper-input float-label label="Address"></paper-input> <paper-input float-label label="State"></paper-input> </paper-item> <paper-item> <paper-input float-label label="Country"></paper-input> <paper-input float-label label="PIN"></paper-input> <paper-input float-label label="Phone (Mobile)"></paper-input> </paper-item> <paper-input float-label label="Phone (Office)"></paper-input> <paper-button raised class="indigo">Submit</paper-button> </form> </iron-form> </div> 能够调用成员函数(将第一个参数传递给隐式std::bind参数),因此您可以将this替换为:

    do_walk
  2. 使std::bind(&Elem::walk, std::placeholders::_1, f) 模板的问题在于walk时,不清楚应该使用哪个实例化。您可以通过显式指定模板参数来消除歧义:

    bind
  3. 我相信std::bind(&Elem::walk<UnaryFunction>, std::placeholders::_1, f) 没问题。

  4. [Live example]使用gcc 4.4.7

答案 1 :(得分:1)

您可以使用std :: function来解决模板遍历问题。 让我们sumarryze:

  

我使用包装函数do_walk和std :: bind来调用该成员   函数遍历每个元素。有没有办法避免包装   函数并直接调用成员函数?

是。使用std :: function

  

我使用typedef作为回调函数UnaryFunction。我会   喜欢使用模板版的walk。但是,当我改变了   代码使用模板我得到以下编译错误:错误:   没有匹配函数来调用'bind(,std :: _ Placeholder&lt; 1&gt;&amp;,void(*&amp;)(const Elem&amp;))'。可能吗   在这种情况下使用模板?

是。使用std :: function + variadic templates

  

也许有一种替代std :: for_each更适合   对于这种树遍历?

我认为std :: for_each可以用于此目的

#include <list>
#include <algorithm>
#include <functional>


struct Elem
{
   std::list<Elem> children; // Some container, std::list for now.

                          //template< class UnaryFunction > // (2)
   template<typename ...TArgs>
   void walk( std::function<TArgs...> f ) const
   {
       // Walk all children.
       std::for_each(
           children.begin(),
           children.end(),
           f ); // (1) NO WRAPPER
   }
};

void pretty_print( const Elem& elem )
{
    // Pretty print element.
}

int main()
{
   Elem root;
   Elem root1;
   root.children.push_back( root1 );

   // Create tree somehow.
   root.walk<void( const Elem& )>( pretty_print );
   // or root.walk<decltype( pretty_print )>( pretty_print ); if you do not 
   // want to clarify type
   return 0;
}