2016-05-19 7 views
1

std :: bindがメンバー関数ポインタとどのように機能するかを理解しようとしています。だから、この例は私には明らかです。C++バインド関数のポインタを使用して

#include<iostream> 
#include<functional> 

using namespace std::placeholders; 

struct Foo 
{ 
    void print_sum(int n1, int n2) 
    { 
     std::cout << n1+n2 << '\n'; 
    } 
}; 


int main() 
{  
    Foo foo; 
    auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1); 
    f3(5); //prints 100 
    return 0; 
} 

_1は5に置き換えられ、関数は期待通りに呼び出されます。

他の例を見てみましょう。この例では、メンバー関数とStd :: FunctionをEffective C++からバインドする方法を組み合わせています。

#include<iostream> 
#include<functional> 

using namespace std::placeholders; 

class GameCharacter; // forward declaration 

int defaultHealthCalc(const GameCharacter& gc) 
{ 
    std::cout<<"Calling default function"; 
    return 10; 
} 

class GameCharacter 
{ 
public: 
    typedef std::function<int (const GameCharacter&)> HealthCalcFunc; 
    explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc) :healthFunc(hcf){} // constructor 
    void setHealthFunction(HealthCalcFunc hcf) 
    { 
     healthFunc = hcf; 
    } 

    int healthValue() const 
    { 
     return healthFunc(*this); 
    } 
private: 
    HealthCalcFunc healthFunc; // pointer to function 
}; 

class EvilBadGuy : public GameCharacter{ 
public: 
    explicit EvilBadGuy(HealthCalcFunc hcf = defaultHealthCalc) : GameCharacter(hcf) {} // constructor 
}; 

class GameLevel{ 
public: 
    GameLevel(int l = 1) : level(l){} 
    int health(const GameCharacter& gc) const 
    { 
     std::cout<<"Calling gamelevel health"<<std::endl; 
     return level * 10000; 
    } 
    void setLevel(int l) { 
     level = l; 
    } 
private: 
    int level; 
}; 

int main() 
{  
    GameLevel currentLevel; // default construct 
    EvilBadGuy ebg3(std::bind(&GameLevel::health, std::cref(currentLevel),_1)); // what is _1 here ? 
    std::cout << ebg3.healthValue() << std::endl; 

    return 0; 
} 

私の主な混乱の原因は、上記のプレースホルダ_1です。何人かは私のためにこれを壊してもいいですか?上記の例では、関数が呼び出されたときに_1が渡された値でしたが、オブジェクトの作成時にこれがどのように解決されるかはわかりません。

ありがとうございました。

+1

あなたはbind_を理解したいと思っていますが、一般的には、lambdaを使ってメンバー関数をラップすることをお勧めします。 –

+1

'F(param)'は 'F(param)'を呼び出す関数オブジェクト( 'F')を生成します: currentLevel.health(param) 'です。このオブジェクトはさらに 'std :: function'でラップされ、渡され、最後に呼び出されます。 –

答えて

1

_1 ... _Nは、彼らがのstd ::プレースホルダであるとしてかなり明白である(プレースホルダです。 は、あなたがそれらを使用することによって何これ関数のパラメータに使用する引数伝えることです。

SomeClasss obj; 
auto f1 = std::bind(&SomeClass::SomeFunction, &obj, _1, _2); 

これはF1の第一引数が第二のparamaterとして使用されます工ass :: SomeFunctionが呼び出された最初のパラメータとf1の2番目の引数として使用されることを意味します。 あなたも今すぐ

SomeClass obj; 
auto f2 = std::bind(&SomeClass::SomeFunction, &obj, _2, _1); 

のように気にいらを行うことができますSomeClass :: SomeFunctionが呼び出されると、f2の最初の引数が2番目のパラメータになり、2番目の引数が最初のパラメータになります。

だから、あなたが

EvilBadGuy ebg3(std::bind(&GameLevel::health, std::cref(currentLevel),_1)) 

で何をすべきか、オブジェクトcurrentLevelにそのhealthFunc beeingてGameLevel ::健康でcontructとEvilBadGuyオブジェクトです。 healthFuncの最初の引数は、GameLevel :: healthに渡される最初のパラメータになります。

+0

私はあなたがf3の代わりにf1を意味すると確信しています.Nit-Pickではなく、&SomeClunctionは、第2引数は常にメンバ関数をバインドするときにここにオブジェクトであるべきですか?説明のために乾杯! – RickMota

関連する問題