2017-02-16 6 views
0

Here's my code:Как я могу «автоматически отправить» экземпляр вызывающего объекта в функцию bind?

#include <iostream> 
#include <functional> 
#include <vector> 

class Voice 
{ 
public: 
    double mVoiceValue = 0.0; 
    std::function<double(Voice &, double)> mTargetFunction; 

    Voice(std::function<double(Voice &, double)> targetFunction) : mTargetFunction(targetFunction) { } 
    ~Voice() { }  

private: 
}; 

class Osc 
{ 
public: 
    double mOscValue = 1.0; 

    Osc() { } 
    ~Osc() { } 

    double Modulate(Voice &voice, double value) { 
     return mOscValue * voice.mVoiceValue * value; 
    } 

private: 
}; 

int main() 
{ 
    Osc *osc = new Osc(); 
    Voice voice1(std::bind(&Osc::Modulate, osc, std::placeholders::_1, std::placeholders::_2)); 
    Voice voice2(std::bind(&Osc::Modulate, osc, std::placeholders::_1, std::placeholders::_2)); 

    voice1.mVoiceValue = 1.0; 
    voice2.mVoiceValue = 2.0; 
    std::cout << "value: " << voice1.mTargetFunction(voice1, 10.0) << std::endl; 
    std::cout << "value: " << voice2.mTargetFunction(voice2, 100.0) << std::endl; 
} 

Я хотел бы не передавая экземпляры voice1/voice2 (т.е. сам) к функции вызова связывания. Поскольку я хотел бы напрямую отправить этот экземпляр, потому что он тот же самого вызывающего объекта.

Как я могу связать таким образом?

т.е. он должен возвращать тот же результаты призванию:

std::cout << "value: " << voice1.mTargetFunction(10.0) << std::endl; 
std::cout << "value: " << voice2.mTargetFunction(100.0) << std::endl; 
+0

Предоставить метод «Голос», который вызывает функцию mTargetFunction (* это, что угодно); '. Затем назовите его как 'voice1.callTarget (10.0);' –

+1

Имейте в виду, что при связывании вы делаете 2 копии объекта 'osc'. – Slava

+0

@Slava: что вы имеете в виду «вы делаете 2 копии osc»? – markzzz

ответ

0

Если это нормально для Voice конструктора принять два аргументов (Osc объекта и указатель функции члена), вы можете решить это что-то вроде этого :

class Voice 
{ 
public: 
    double mVoiceValue = 0.0; 
    std::function<double(double)> mTargetFunction; 

    template<typename T, typename F> 
    Voice(T& targetObject, F&& targetFunction) 
     : mTargetFunction(std::bind(targetFunction, targetObject, std::ref(*this), std::placeholders::_1)) { } 
    ~Voice() { } 
}; 

class Osc 
{ 
public: 
    double mOscValue = 1.0; 

    Osc() { } 
    ~Osc() { } 

    double Modulate(Voice &voice, double value) { 
     return mOscValue * voice.mVoiceValue * value; 
    } 
}; 

... 

Osc osc; 
Voice voice1(osc, &Osc::Modulate); 
Voice voice2(osc, &Osc::Modulate); 

voice1.mVoiceValue = 1.0; 
voice2.mVoiceValue = 2.0; 
std::cout << "value: " << voice1.mTargetFunction(10.0) << std::endl; 
std::cout << "value: " << voice2.mTargetFunction(100.0) << std::endl; 

важный бит здесь является использование std::ref для Voice аргумента.

Если это всегда функция Modulate элемент, который будет называться, то Voice конструктор не должен принимать указатель на функцию-член в качестве аргумента, а затем использовать &T::Modulate в вызове std::bind.

+0

Я не хочу использовать шаблон. – markzzz

+0

@paizza Тогда, если вы не будете * всегда * использовать 'Osc', у вас действительно нет выбора: либо ваше решение, либо мое решение с шаблонами. Из вас * будут * использовать * объекты Osc', а затем сделать декларацию вперед и использовать жесткий код. Опционально создайте несколько перегрузок конструктора 'Voice', каждый из которых принимает указатель на функцию-член для каждого объекта, который вы можете использовать. –

+0

Что значит «вы всегда будете использовать Osc»? Я хочу использовать функцию 'Osc :: Modulate'' osc' для каждого голоса. Раб сказал: «Имейте в виду, что вы делаете 2 копии объекта osc при связывании». Не уверен, что он имеет в виду. Может быть, это связано? – markzzz