如何调用具有for_each循环参数的函数?

时间:2015-02-10 16:50:52

标签: c++ foreach

我有一个C ++程序,它将对象存储在向量中,然后使用std::for_each在每个对象上调用一个函数。如果被调用函数需要参数,我不明白如何编写std::for_each循环。

以下是我想要使用的代码示例:

#include <vector>
#include <algorithm>
#include <functional>

class BaseClass
{
    public:
        virtual void Setup() = 0;
        virtual void DisplayText(int key, int x, int y) = 0;
};

class A: public BaseClass
{
    public:
        void Setup();
        void DisplayText(int key, int x, int y);
};

class B: public BaseClass
{
    public:
        void Setup();
        void DisplayText(int key, int x, int y);
};

void demo(A *a, B *b, std::vector<BaseClass*>& storageVector)
{
    storageVector.push_back(a);
    storageVector.push_back(b);

    std::for_each (storageVector.begin(), storageVector.end(),
        std::mem_fn(&BaseClass::Setup));

    std::for_each (storageVector.begin(), storageVector.end(),
        std::mem_fn(&BaseClass::DisplayText));
}

我从编译器中得到这些错误:

error C2064: term does not evaluate to a function taking 1 arguments
error C2752: 'std::_Result_of<_Fty,_V0_t,_V1_t,_V2_t,_V3_t,_V4_t,
    _V5_t,<unnamed-symbol>,_Obj>' : more than one partial
    specialization matches the template argument list

如果我尝试将参数传递给函数,例如

for_each (storageVector.begin(), storageVector.end(),
    std::mem_fn(&BaseClass::DisplayText(0,0,0)));) 

然后我也得到了

error C2352: 'BaseClass::DisplayText' :
    illegal call of non-static member function

我错过了什么?

4 个答案:

答案 0 :(得分:4)

函数DisplayText需要三个未提供的附加参数。你需要:

更改DisplayText不要求任何参数

或者使用提供它们的lambda:

for_each(storageVector.begin(), storageVector.end(),
   [](BaseClass* c){ c->DisplayText(key, x, y); });

或者使用for-each提供它们的循环:

for (auto c : storageVector)
    c->DisplayText(key, x, y);

或者将参数绑定到仿函数:

for_each(storageVector.begin(), storageVector.end(),
    std::bind(std::mem_fn(&BaseClass::DisplayText), _1, key, x, y));

答案 1 :(得分:3)

您可以使用lambda函数。

std::for_each (storageVector.begin(), storageVector.end(), [] (BaseClass* base) {base->Setup();});
std::for_each (storageVector.begin(), storageVector.end(), [] (BaseClass* base) {base->DisplayText(1, 2, 3);});

您可以在http://en.cppreference.com/w/cpp/language/lambda了解有关lambda函数的更多信息。

答案 2 :(得分:1)

您需要将一些参数绑定到函数DisplayText,该函数需要3个参数keyxy。有多种方法可以做到这一点。例如,您可以创建自己的仿函数对象来执行绑定,也可以使用lambda。

最简单的方法是将常量值绑定到参数,但您也可以绑定基于某些外部信息计算的值。无论哪种方式,您都可以在不提供其所有参数的情况下调用DisplayText

在你的第二个例子中,你试图&#34;取地址&#34;带参数的函数你不能直接在C ++中这样做。其他一些语言直接允许您绑定一些小于函数声明参数的实际数量的参数,这个概念称为currying。在不支持这种情况的语言中,典型的方法是使用闭包来存储附加参数的状态,并允许稍后调用闭包。这个功能是C ++ 11的lambda支持的。

for_each期望一个函数只接受一个参数,但是你给它一些不同的东西,这就是你的错误所说的。 std::mem_fn接受一个成员函数并将其转换为一个非成员可调用对象,该对象带有一个额外的参数。这意味着你现在给for_each一些需要4个参数而不是1个参数的东西。第一个参数是要调用的对象,另外3个参数是DisplayText期望的原始参数。

我将向您展示仿函数对象方法,因为即使在旧版本的C ++中它也能正常工作,实际上它是std::function和lambda对象在封面下工作的方式。 C ++ 11有一种新的语法,可以更加轻松地执行此操作,但理解它的工作方式对于理解新语法很有用。

class F {
public:
    F(int key, int x, int y) : key(key), x(x), y(y) {}

    void operator()(BaseClass *d) const {
        d->DisplayText(key, x, y);
    }

private:
    int key;
    int x;
    int y;
};

for_each(storageVector.begin(), storageVector.end(), F(1, 2, 3));

如果你这样做的话,你会发现自己写了很多这些一次性扔掉的类,他们所做的就是存储一些具有特定类型签名的给定数量的参数。意识到这一点,你可以通过模板化参数的类型来概括这个类。更进一步,您可以通过采用可变数量的模板参数并因此支持可变数量的参数来进一步概括它。这正是std::function类型的工作方式。

答案 3 :(得分:0)

从cppreference.com,您的函数签名应为void fun(const Type &a)。我认为问题可能是您的签名要么不接受任何参数(在Setup的情况下),要么接受多个参数(在DisplayText的情况下),而不是for_each是什么期待。

您可能需要:

void my_func(const BaseClass &r_arg) {};