我很擅长在C ++中使用algorithm
和functional
。我需要进行树遍历并为每个元素执行一个函数。请参阅下面的代码。
这样可行,但是我有一些我不喜欢的东西,或许可以做得更好。请注意,我仅限于相当旧版本的g ++(4.4.7),不能使用lambda函数。
我使用包装函数do_walk
和std::bind
来调用每个元素上的成员函数walk
。有没有办法避免包装函数并直接调用成员函数?
我使用typedef作为回调函数UnaryFunction
。我更喜欢使用walk
的模板版本。但是,当我更改代码以使用模板时,我得到以下编译错误:error: no matching function for call to 'bind(<unresolved overloaded function type>, std::_Placeholder<1>&, void (*&)(const Elem&))'
。是否可以在此上下文中使用模板?
也许有std::for_each
的替代品更适合这种树遍历?
到目前为止我的代码:
#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;
}
答案 0 :(得分:6)
<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
使std::bind(&Elem::walk, std::placeholders::_1, f)
模板的问题在于walk
时,不清楚应该使用哪个实例化。您可以通过显式指定模板参数来消除歧义:
bind
我相信std::bind(&Elem::walk<UnaryFunction>, std::placeholders::_1, f)
没问题。
[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;
}