2012-12-10 29 views
6

Bu sorunun daha önce sorulmuş olduğunu biliyorum, ancak oldukça deneyimli bir kodlayıcı olmasına rağmen, yanıtları anlamıyorum ve sormak için bu önceki sorulara yanıt vermenin bir yolunu görmüyorum açıklama. "Cevap" bağlantısı yok ya da bir şey yok. Ayrıca, bu sorular oldukça eskiydi. Yani, ben soruyu yeniden soruyorum.C++ 'da std :: function imzası üzerine aşırı yüklenme nasıl yapılır?

+ = operatörünü aşırı yüklediğim bir sınıfa sahibim. Bir aşırı yük çıplak işlev işaretçisi almak istiyorum, ve diğer bir std :: işlevi almaya:

void operator+=(void (*handler)()); 
void operator+=(function<void (void *, T)> handler); 

Kullanımı: derleyici belirleyemiyor çünkü

MyClass a; 
a += [](){ DoSomething(); }; 
a += [](void *x, T y){ DoSomething(); }; 

Maalesef kod derleme değil ikinci aşırı yükün ilk + = çağrı için uygun olmadığı.

Bu sorunu gidermek için operatör + = üye işlevlerimi nasıl tanımlarım? Operatörlerin nasıl kullanıldığını değiştirmek istemiyorum (ör. Açık bir yayın kullanarak). Yukarıda gösterildiği gibi çalışmasını istiyorum.

void operator+=(function<void()> handler); 

Ama yine, ben işlevi <> şablon imzası dayalı aşırı yük olamaz:

Buna ek olarak, aynı zamanda aşağıdaki aşırı olması kullanışlı olurdu.

diğer örnekler için bu thread bakınız: Isn't the template argument (the signature) of std::function part of its type? (O parçacığı belirtilen çeşitli çözümler uygulayan çalıştı ve bunlardan hiçbiri derlemek olurdu) Ben bir dizi uzun yıllar programlama oldum

diller, ama benim C++ becerilerim biraz paslı.

+0

** büyük ** soru şudur: __what, belirli bir işlev göstergesini veya "std :: function" nesnesini, aşırı yükünüzde yapacaksınız, operatör + = '? __ – zaufi

+0

@zaufi: Nasıl olduğunu göremiyorum Bu alakalı, ama tamam. Bunu std :: event handler işlevlerine ekleyeceğim. Esasen .NET olaylarını C++ uygulamasında yapıyorum. Çünkü bu güçler, kafalarını, Olaylar ve Özellikler gibi, Kapanışlar gibi, modern bir programlama dili için kesinlikle gerekli işlevsellikler etrafında sarmıyorlardı. –

+0

öyleyse, o zaman bir std :: vector' ile std :: function' ile tam olarak bir tane ('void() ') imzası imzalı bir imzanız olmalıdır. Doğru muyum? – zaufi

cevap

3

4.7.2 g ++ iyi kodu çalışır aşağıdakı:

#include <functional> 
#include <iostream> 

template <typename T> 
typename std::enable_if<std::is_convertible<T, void(*)()>::value>::type 
foo(T&&) 
{ 
    std::cout << "foo(void(*)())" << std::endl; 
} 

void foo(std::function<void(void*,int)>) 
{ 
    std::cout << "foo(std::function<void(void*,int)>)" << std::endl; 
} 

int main() 
{ 
    foo([]{}); 
    foo([](void*,int){}); 
} 

sorun template <class F> function(F); olarak bildirilmiş std::function yapıcısı, kaynaklanır. Bu kurucu her şeyi argümanı olarak kabul eder. Bu argüman uygun bir operator() değilse, kurucunun başlatılması sırasında bir hata oluşturulur.

Ne yazık ki aşırı yük çözme işlemi herhangi bir şablon işlevinin başlatılmasını gerektirmiyor, bu nedenle derleyici her şeyin std::function türüne dönüştürülebileceğine inanıyor.

+0

Teşekkürler, sadece bunu sınıfımın içine problemsiz bir şekilde almayı başardım; Her ne kadar bir işlevi T'yi yapmaya çalışmamda biraz kıllı olsa da <>. Görünüşe göre, önce bir boşluk (*)() kullanmalıyım. Şerefe. –

+0

Sanırım yaşadığım temel sorun, enable_if'i hiç duymadığım ve bunu anlamadığı. Nasıl yardımcı olabileceğinin farkındaydım (cevapları benzer sorulara bakarak), fakat nasıl kullanıldığını bilmiyordum. Hala nasıl çalıştığından emin değilim. –

+0

'enable_if' hakkında bazı bilgiler [burada] bulunabilir (http://www.boost.org/doc/libs/1_52_0/libs/utility/enable_if.html) ve [burada] (http: //en.cppreference com/ağırlık/cPP/türleri/enable_if). – hpsMouse

0

Tamam, eğer bir std::vector<std::function<void()>> varsa, bir sürü aşırı yüklemenize bile gerek yoktur. En basit yol, std::enable_if ile "korunan" olası bir şablon operator+= tanımlamaktır, sadece yanılabilir nesne veya işlev işaretçileri için AÇIK olmalıdır. Yani lambda veya ham işaretçiler geçerken atamanız için otomatik dönüştürme yapar (push_back/emplace_back). std::function geçişi yalnızca beklendiği gibi atayacaktır.

+0

Noktayı kaçırıyorsunuz. "[]() {}" Lambdas ve "[] (void *, T) {}" lambdaslarını vektörüme eklemek istiyorum. Onları ortak bir kapsayıcı sınıfına alıyorum ve bunu benim vektörüme ekliyorum. Beni farklı lambda imzalarına ihtiyacım olmadığına inandırmaya çalışmak, zamanın ve benimkilerin boşa harcanması. –