Kuvvetlendirme kullanabiliyorsa, sinyaller-yuvaları/olayları/gözlemciler işlevsellik sağlar Boost.Signals2 kullanmayı düşünün. Bu basit ve kullanımı kolaydır ve oldukça esnektir. Boost.Signals2 ayrıca, keyfi olarak yüklenebilen nesneleri (örneğin, funktörler veya ciltli üye işlevleri gibi) kaydetmenize izin verir, böylece daha esnektir ve nesne yaşamlarını doğru şekilde yönetmenize yardımcı olacak birçok işleve sahiptir.
Eğer bunu kendiniz yapmaya çalışıyorsanız, doğru yoldasınız demektir. Yine de bir probleminiz var: Tam olarak, kayıtlı fonksiyonların her birinden dönen değerler ile ne yapmak istersiniz? Yalnızca bir değeri operator()
'dan döndürebilirsiniz, böylece hiçbir şey mi yoksa sonuçlardan mi yoksa sonuçların bir şekilde mi toplanacağına karar vermelisiniz.
Sonuçları göz ardı etmek istediğimiz varsayarsak, bunu uygulamak oldukça basittir, ancak her bir parametre türünü ayrı bir şablon türü parametresi olarak alırsanız biraz daha kolay olur (alternatif olarak, Boost.TypeTraits gibi bir şey kullanabilirsiniz), hangi kolayca) bir işlev türünü incelemek sağlar:
template <typename TArg0>
class MyEvent
{
typedef void(*FuncPtr)(TArg0);
typedef std::deque<FuncPtr> FuncPtrSeq;
FuncPtrSeq ls;
public:
MyEvent& operator +=(FuncPtr f)
{
ls.push_back(f);
return *this;
}
void operator()(TArg0 x)
{
for (typename FuncPtrSeq::iterator it(ls.begin()); it != ls.end(); ++it)
(*it)(x);
}
};
Bu void
dönüş türü kayıtlı işlevi gerektirir. Herhangi bir geri dönüş türü ile işlevlerini kabul edebilmek için, FuncPtr
typedef std::function<void(TArg0)> FuncPtr;
olmak değiştirmek (veya C++ 0x sürümü kullanılabilir yoksa boost::function
veya std::tr1::function
tuşlarını kullanarak). Dönüş değerleri ile bir şeyler yapmak istiyorsanız, döndürme türünü başka bir şablon parametresi olarak MyEvent
'a alabilirsiniz. Bu yapmak için nispeten basit olmalıdır.
void test(float) { }
int main()
{
MyEvent<float> e;
e += test;
e(42);
}
Eğer olayların farklı arities desteklemek sağlayan bir diğer yaklaşım, fonksiyon tipi için tek bir tip parametre kullanmak olacaktır ve:
yukarıdaki uygulamayla
aşağıdaki çalışması gerekir Her biri farklı sayıda argüman alan aşırı yüklenmiş operator()
aşırı yük var. Bu aşırı yükler şablonlar olmalı, aksi takdirde olayın gerçek aritesine uymayan aşırı yüklenmeler için derleme hataları alırsınız. İşte işe yarar bir örnek:
template <typename TFunc>
class MyEvent
{
typedef typename std::add_pointer<TFunc>::type FuncPtr;
typedef std::deque<FuncPtr> FuncPtrSeq;
FuncPtrSeq ls;
public:
MyEvent& operator +=(FuncPtr f)
{
ls.push_back(f);
return *this;
}
template <typename TArg0>
void operator()(TArg0 a1)
{
for (typename FuncPtrSeq::iterator it(ls.begin()); it != ls.end(); ++it)
(*it)(a1);
}
template <typename TArg0, typename TArg1>
void operator()(const TArg0& a1, const TArg1& a2)
{
for (typename FuncPtrSeq::iterator it(ls.begin()); it != ls.end(); ++it)
(*it)(a1, a2);
}
};
(burada C++ 0x dan std::add_pointer
kullandım, ancak bu tür değiştirici ayrıca Boost ve C++ TR1 bulunabilir; bu sadece o işlevi kullanmak için biraz daha temiz hale getirir . mümkündür, ancak mevcut tasarımı ile
void test1(float) { }
void test2(float, float) { }
int main()
{
MyEvent<void(float)> e1;
e1 += test1;
e1(42);
MyEvent<void(float, float)> e2;
e2 += test2;
e2(42, 42);
}
'aşırı etmeyin operatörü + =', bunu son derece kafa karıştırıcı buluyorum . – fredoverflow
Bkz http://www.codeproject.com/KB/cpp/ImpossiblyFastCppDelegate.aspx sorunun –
biri C++ doğrudan C# stil olayların merkezi parçası olan delege, desteklemediği olmasıdır. http://www.codeproject.com/KB/cpp/FastDelegate.aspx Delegeleri standart olmayan, ancak çoğu derleyici tarafından desteklenen bir şekilde uygular. – CodesInChaos