2011-07-08 14 views
5

Sıralı bir dizi işlev nesnesini sırayla yürütecek bir mekanizma tasarlıyorum. Bu işlev nesneleri çalışma zamanı sırasında atanır ve sorun şu şekildedir: Bu işlev nesnesinin parametre türü farklıdır. Yapmak istediğim neSırayla farklı parametre türlerinin tekil işlevli nesneleri nasıl yürütülür?

böyle bir şeydir:

class command_sequence { 
private: 

/* some kind of container */ 

public: 
    void add(FUNC_OBJ &func, PARAM val); 
    void run(void); 
}; 

class check_temperature { 
public: 
    void operator() (int celsius) { 
     if(celsius > 26) { 
      cooler.switch_on(); 
     } 
    } 
}; 

class log_usage { 
public: 
    void operator() (std::string username) { 
     username.append(" logged in"); 
     syslog(LOG_NOTICE,username.c_str()); 
    } 
}; 

command_sequence sequence; 
log_usage logger; 
check_temperature checker; 

sequence.add(logger, std::string("administrator")); 
sequence.add(checker, lobbyMeter.read_temperature()); 
sequence.add(logger, std::string("lecture")); 
sequence.add(checker, classroomMeter.read_temperature()); 
sequence.run(); 

C kodu yazıyorum, ben parametre olarak * hükümsüz sürer hiçbir seçim ama geri çağırma işlevi işaretçisi var. Ama şimdi C++ ile çalışıyorum, bununla başa çıkmak için şık bir yol olmalı. Şimdi düşünebiliriz

iyi yolu neredeyse bir soyut sarıcı sınıftan kalıtımla bir şablon sınıfını ilan edilir: Bu yaklaşım ihtiyaçlarımı sığabilecek

class command_sequence { 
private: 

    class runner { 
    public: 
     virtual void execute(void) = 0; 
    }; 

    template <class FUNC, typename T> class func_pair : public runner { 
    private: 
     FUNC &func; 
     T param; 
    public: 
     func_pair(FUNC &f, const T &t) : func(f),param(t) { } 
     void execute(void) { 
      func(param); 
     } 
    }; 

    std::vector<runner*> funcQueue; 

public: 

    template <class FUNC, typename T> void add(FUNC &obj, const T &t) { 
     funcQueue.push_back(new func_pair<FUNC,T>(obj,t)); 
    } 

    void run(void) { 
     std::vector<runner*>::iterator itr=funcQueue.begin(); 
     for(;itr!=funcQueue.end();++itr) { 
      (*itr)->execute(); 
      delete (*itr); 
     } 
    } 
}; 

, ancak tahsis ve her giriş için template_pair serbest olacaktır. Bu işlemin bellek parçasına neden olup olacağına dair hiçbir fikrim yok, çünkü bu işlem süreçte oldukça sıkça çağrılacak.

Bunu yapmanın daha iyi bir yolu var mı?

cevap

4

o tekli işlevine argüman sen dizisine eklemek anda sabittir gibi göründüğünden, size dizisi boost::function kullanarak sıfır argüman fonksiyon nesneleri kabul ardından boost::bind gerekli parametreyi yapabilir, örneğin Eğer otomatik fonksiyon nesnenin dönüş türü anlamak edemez çünkü boost::bind çağrısına bir şablon parametresi olarak <void> belirtmek zorunda

class command_sequence { 
public: 
    void add(boost::function<void(void)> functor); 
}; 

/* ... as before ... */ 

log_usage logger; 
check_temperature checker; 

sequence.add(boost::bind<void>(logger, "administrator")); 
sequence.add(boost::bind<void>(checker, lobbymeter.read_temperature())); 

Not. Alternatif olarak, bu çözüm gerçekten artışı için bir deyim olan yani :: işlevini()

class log_usage 
{ 
public: 
    typedef void result_type; 
    void operator() (const std::string& message) 
    { 
     // do stuff ... 
    } 
}; 

/* ... */ 

sequence.add(boost::bind(logger, "blah")); // will now compile 
+0

Gerçekten etkileyici. Boost :: bind() işlev nesnelerini kabul edebileceğini hiçbir fikrim yok; ama mantıklı. Bu aradığım cevap gibi görünüyordu. Teşekkürler. – RichardLiu

7

Bir işlev nesnesini ve bağımsız değişkenini ayrı ayrı geçirmeniz gerekiyor mu? Ben aşağıdaki gibi görünen bu durumda, boost::bind kullanmak: Bu durumda command_sequence yılında

void check_temperature(int celsius) 
{ 
    if(celsius > 26) { 
     cooler.switch_on(); 
    } 
}; 

void log_usage(std::string username) 
{ 
    username.append(" logged in"); 
    syslog(LOG_NOTICE,username.c_str()); 
}; 

// keep actions 
typedef std::vector< boost::function<void()> > func_arr_t; 
func_arr_t actions; 
actions.push_back(boost::bind(&log_usage, "administrator")); 
actions.push_back(boost::bind(&check_temperature, lobbyMeter.read_temperature())); 
actions.push_back(boost::bind(&log_usage, "lecture")); 
actions.push_back(boost::bind(&check_temperature, classroomMeter.read_temperature())); 

// run all 
for (func_arr_t::const_iterator it = actions.begin(); it != actions.end(); ++it) 
    (*it)(); 

sadece fonksiyon nesneleri dizisi tutacak.

+0

Teşekkür Bu kaçınır sınıf tanımında result_type adında bir kamu typedef maruz bırakabilir, ama bir nesne geçmek gerekiyordu Benim örneğimde. Bir işlev nesnesi, başka bir sınıfta bileşik sınıf olarak bildirilebilir ve kapsayıcı sınıfın bazı özel üyelerini tutabilir. Örneğin, gerçek kodlarımda "check_temperature" işlev nesnesi, üye değişken olarak "cooler" hedefine bir soket dosyaidini de tutar. – RichardLiu

İlgili konular