函数迭代成员并调用作为参数传递的函数

时间:2010-12-10 13:36:44

标签: c++ templates function-pointers

我有某种类型的std::vector<T>是类的一部分,我需要在代码中的许多不同位置进行迭代,所以我认为我会聪明并创建一个函数IterateAttributes,并传递一个boost :: function对象,我可以在循环中传递一个元素,然后我可以传递任何函数来处理元素。

这似乎是一个好主意,直​​到你必须实现它,然后问题来自传入的函数返回什么,它需要其他参数。看起来我要么必须找到一种更通用的方法,比如使用模板,或者我必须创建带有不同args的函数对象的重载。

我认为第一个(更通用的)选项可能更好,但是我怎么做呢?

下面是一个不起作用的试验,但是如果我想要一些args,除了属性(结构)arg之外的所有arg都是必需的。我应该怎么做呢?

template <typename T> template <typename arg>
void ElementNode::IterateAttributes(boost::function<T (arg, Attribute)> func_)
{
    std::vector<Attribute>::iterator it = v_attributes.begin();

    for (; it != v_attributes.end(); it++)
    {
        func_(arg, *it);
    }
}

4 个答案:

答案 0 :(得分:1)

这就是你的意思:

template <typename T, typename arg>
void ElementNode::IterateAttributes(boost::function<T (arg, Attribute)> func_, arg a)
{
    std::vector<Attribute>::iterator it = v_attributes.begin();

    for (; it != v_attributes.end(); it++)
    {
        func_(a, *it);
    }
}

只允许任何类型的一个参数 - 如果您愿意,还可以引入更多参数的版本。

关于返回值 - 如何处理它取决于它实际上是什么价值 - 通用(可能是不必要的)解决方案是返回std::list<T>,但这会产生比我想象的更多的问题。如果返回类型不同(不仅在类型上,而且在含义上),那么我建议修改模板化函数,以便它获取整体结果的引用/指针并相应地更新它:

template <typename T> template <typename arg>
void ElementNode::IterateAttributes(boost::function<voidT (arg, Attribute, T&)> func_)
{
    std::vector<Attribute>::iterator it = v_attributes.begin();
    T result;

    for (; it != v_attributes.end(); it++)
    {
        func_(arg, *it, result);
    }
    return result;
}

这是一个快速的解决方法,它可以工作,但它很难看,容易出错,也很难调试。

如果你想要变量参数金额,那么你必须创建以上函数的几个模板 - 我只是测试了它是否可能:

template <typename T>
 T boo(T){

}

template <typename T, typename TT>
TT boo(T,TT){

}

void test()
{
    int i;
    i= boo<int>(0);
    i=boo<int,double>(0,0.0);
}

您必须记住,传递给IterateAttributes的函数必须与给予Iterate函数的exatly参数匹配。这也意味着你不能使用它的原型默认值 - 可能你必须定义几个重载版本,如

void func_(Attribute,arg1, arg2,arg3){...}
void func_(Attribute A,arg1 a1,arg2 a2){func_(A,a1, a2,default3);}
void func_(Attribute A,arg1 a1){func_(A,a1, default2,default3);}
void func_(Attribute A){func_(A,default1, default2,default3);}

答案 1 :(得分:0)

a)你想迭代数组并对那里的每个元素做一些事情:在这种情况下,你想要所有接受数组元素并返回void的函数。简单。

b)您希望在每个元素上部分应用具有更多参数的函数:在函数周围编写一个自定义函子来存储其他预先赋值的参数,或者使用boost::bind来有效地执行相同操作。

示例:

vector<string> myStrings; // assign some values

// define a function with an additional argument
void myFunc(string message, string value)
{
  cout << message << value << endl;
}

// allow partial application, i.e. "currying"
struct local_function
{   
  static string message;

  static void myFunc_Curried(string value)
  {
    myFunc(message, value);
  }    
};

local_function::message = "the array contains: ";

// apply the curried function on all elements in the array
for_each(myStrings.begin(), myStrings.end(), local_function::myFunc_Curried);

仿函数仅用于演示目的而静态运行。如果将message绑定到结构的实例,则无论如何都需要类似boost::bind的绑定实例指针this以实际调用curried函数。但是,如果我想要应用的函数仅在本地使用,我更喜欢使用更易读的静态方法。

您要完成的工作非常有意义,并且还直接构建到函数式语言中(例如F#)。可以用C ++实现,但在上述情况b中需要一些变通方法。请注意,如果在我的示例中编写自己的仿函数,通常会将您想要的参数始终放在开头,并在部分应用时从开头到结尾“填写”参数。 / p>

答案 2 :(得分:0)

总结评论和更多想法:

使用bind绑定其他参数,然后在生成的仿函数上使用for_each

要处理返回值,您需要考虑返回值的含义。如果您需要以某种方式使用这些值(例如,执行缩小,或使用它们来影响是否继续执行操作等),那么您可以使用另一个仿函数来包装原始文件以执行您想要的操作

答案 3 :(得分:0)

您可以使用BOOST_FOREACH或C ++ 0x for each执行相同或更多操作。这甚至可以用更少的代码来编写。