2015-01-03 40 views
10

foo çağrısı belirsiz olduğu söylenir çünkü bu, derleme değilFonksiyon aşırı yük kullanarak lambda fonksiyonu imza

void foo(const std::function<int()>& f) { 
    std::cout << f() << std::endl; 
} 

void foo(const std::function<int(int x)>& f) { 
std::cout << f(5) << std::endl; 
} 

int main() { 
    foo([](){return 3;}); 

    foo([](int x){return x;}); 
} 

aşağıdaki örneği inceleyin. Anlayabildiğim kadarıyla, bu lambda işlevi bir std::function priori değil, ama o döküm edilmeli ve keyfi bir argüman alır bir std::function yapıcı vardır. Birisi bana neden herhangi birinin keyfi bir argümanı alan örtülü bir kurucu oluşturacağını açıklayabilir. Ancak benim akut soru, bir foo fonksiyonunu aşırı yüklemek için lambda fonksiyonlarının fonksiyon imzasını kullanmasına izin veren bir geçici çözüm olup olmadığıdır. İşlev işaretçileri denedim, ancak bu işe yaramadı çünkü lambda işlevlerini yakalamak normal bir işlev işaretçisine dönüştürülemiyor.

Herhangi bir yardım en hoş geldiniz.

+7

Bu muhtemelen MSVC'de bir hatadır. Clang/GCC'de çalışır. –

+2

Oh Microsoft, çok eğlenceli –

+0

[Benim için çalışıyor] (http://ideone.com/XmAgLG). Hangi derleyiciyi kullanıyorsunuz? –

cevap

15

Derleyiciniz, C++ 11'e göre doğrudur. C++ 14'te, argüman türü aslında std::function argüman türleri ile değiştirilemediği sürece, kurucu şablonunun aşırı yüklenmeye katılmayacağını söyleyen bir kural eklenir. Bu nedenle, bu kod C++ 14'te derlenip C++ 11'de derlenmemelidir. Bunu C++ 11'de bir gözetleme olarak düşünün.

Şimdilik, açık dönüşüm ile bu çalışabilirsiniz:

foo(std::function<int()>([](){return 3;})); 
+0

Açıklama için teşekkürler. Yorumların ardından GCC 4.8 (ve -std = C++ 11') kullanarak denedim ve çalıştı. Her nasılsa, GCC'nin daha yeni sürümü bu yüzden kesinlikle doğru C++ 11 kullanmaz. – Haatschii

+1

@Haatschii C++ 11 standardında bir kusur; derleyici/kütüphane devleri genellikle geriye dönük olarak düzeltmeler uygular.(Ayrıca, yine de C++ 11'de UB idi, bu yüzden C++ 14 davranışına izin verilebilir.) –

4

http://coliru.stacked-crooked.com/a/26bd4c7e9b88bbd0

alternatif std için :: fonksiyon şablonları kullanmaktır. Şablonlar std :: function ile ilişkili bellek ayırma yükünden kaçınır. Şablon tipi kesinti makineleri, arama sahası kalıbının ortadan kalkması için iletilen lambda'nın doğru türünü çıkartacaktır. Bununla birlikte, hala sahip olduğunuz, arketörlerin kasalarına karşı aşırı yükleri ortadan kaldırır.

Bunu, enable_if ile benzer davranan son dönüş türlerine sahip bir numara kullanarak yapabilirsiniz.

template<typename Callable> 
auto baz(Callable c) 
    -> decltype(c(5), void()) 
{ 
    std::cout << c(5) << std::endl; 
} 

Baz yukarıda aşırı yük yalnızca şablon parametresi Callable bunu yapmak için bu üstündeki daha gelişmiş mekanizmalar koyabilirsiniz 5.

bir argümanla çağrılabilir geçerli bir aşırı yük aday olacak daha genel (yani, uyumsuzluğa dönüşen değişkenli paket genişlemesi) ancak temel mekanizmanın çalışmasını göstermek istedim.

İlgili konular