2012-09-22 11 views
5

Sağlanan bir lambda'yı çağıran bir işlev sağlamaya çalışıyorum ve işlev void döndürme türüne sahipse, varsayılan değeri döndürüp döndüremeyeceğini merak ediyorum. İşte C++ 11'deki dönüş değeriyle eşleşmenin herhangi bir yolu var mı?

Şu ana kadar lambda dönüşü değer döndüren bir fonksiyona sahiptir ama lambda void ise, o zaman, 20.

#include <functional> 
#include <iostream> 

template <typename H> 
auto f(H&& h) -> decltype(h(), void()) 
{ 
    return h(); 
} 

template <typename H> 
auto f(H&& h) -> decltype(h(), int()) 
{ 
    h(); 
    return 20; 
} 

int main() 
{ 
    int r = f([](){ std::cout << "test1" << std::endl; return 10; }); // error here 
    std::cout << "r: " << r << std::endl; 
    r = f([](){ std::cout << "test2" << std::endl; }); 
    std::cout << "r: " << r << std::endl; 

    return 0; 
} 

Bu hatayı üretir döndürür ne

test.cpp:20:68: error: call of overloaded ‘f(main()::<lambda()>)’ is ambiguous 

Açıkçası bu, C++ 'nın dönüş türüne göre polimorfizm kullanamamasından kaynaklanmaktadır. Ancak, bu mümkün olabilir decltype veya bazı şablon sihir daha iyi kullanımı gibi iyi C++ 11 hileler varsa merak ediyorum? Buraya kadar gerçek bir belirsizlik görmediği için soruyorum çünkü derleyici void geri dönüş türünü çıkarıyor ve daha sonra biraz aptalca olan f'un int veya void versiyonunu eşleştirmek için belirsiz olduğunu söylüyor.

Bunu yapmanın bir nedeni işlevi f bir dönüş değeri bekler ancak kullanıcı bir return deyimi içermeyen bir lambda sağlıyorsa, derleyici bir void türü infers ve hatalar dışarı olmasıdır. Gerçek senaryoda, kullanıcı bir tane sağlamayı umursamadığında makul bir varsayılan getiri değerinin ne olması gerektiğine dair iyi bir fikrim olduğu için, derleyicinin kullanıcıların sıklıkla gereksiz olan return bildirimini ihmal etmesine izin verilip verilmediğini merak ediyorum kolaylık için.

Teşekkürler. GCC 4.6.3 kullanıyorum bahsetmeliyim.

Cevap:

template <typename H> 
auto f(H&& h) -> typename std::enable_if<std::is_same<decltype(h()), void>::value, int>::type 
{ 
    h(); 
    return 20; 
} 

template <typename H> 
auto f(H&& h) -> typename std::enable_if<std::is_same<decltype(h()), int>::value, int>::type 
{ 
    return h(); 
} 

teşekkür: enable_if kullanmanın xeo önerisine dayanarak, işe görünüyor aşağıdaki ile geldi!

+0

normal fonksiyonlarına f test ettik aswell

f([]{}); 

çalışmalarını yapar? – CharlesB

+0

Evet, normal fonksiyonlarda da belirsiz. – Steve

+0

'decltype' ın ikinci parametresi: Ne için olduğunu sorabilir miyim? (Gerçekten, bilmiyorum çünkü). – 0x499602D2

cevap

3

std :: enable_if dosyasını kullanabilirsiniz.

İade tipiniz birincisi için std::enable_if<!std::is_same<decltype(h()), void>::value, decltype(h())>:type, ikincisi için std::enable_if<std::is_same<decltype(h()), void>::value, int>::type olacaktır. Bu kodunuzun çalışmasını sağlamalı. Ben test etmedim, bu yüzden tamamen çalışıp çalışmadığından emin değilim.

+0

Korkarım hala "belirsiz" hatasını döndürüyor. – Steve

+0

@Steve: Hayır, bu doğru çalışıyor. Sanırım bir yerlerde bir yazım hatası olabilir. Bkz. [This] (http://liveworkspace.org/code/e0c94a11d120300743e202f4daec8a66). – Xeo

+0

@Xeo: Teşekkürler, sanırım, JKor'un çözümünün ilk bölümündeki “decltype (h())”, f() 'için dönüş değerini değiştirdiğinden sorunluydu. Örneklerinize göre çalışıyorum, kodu soruya göndereceğim. – Steve

2

Derleyicinin, niçin bu işlevin içinde yaptığınıza bağlı olarak hangi aşırı yüklenmenin seçildiğini anlayabilmesi için bana bir neden verin. C++ 'da, aşırı yük çözünürlüğü yalnızca her bir argüman bir parametreye uygunsa, ilgilenir. Dönüş tipi ve işlev içeriği ile hiç ilgilenmiyor.

As STL says:

TLDR: Şablonlar açgözlü! Ne olacağından emin olmadıkça onları aşırı yüklemeyin.

Ve bir evrensel başvuru kaynağı (template<class T> void f(T&&);), alabileceğiniz en grevdir.

Sen @JKor SFINAE diyor gibi çözmek, ancak basitleştirilmiş olabilir: GCC 4.7 decltype(int(void_returning_function())) fonksiyonu dışında SFINAE neden olmaz bir hata olduğunu

#include <type_traits> 

template<class F> 
auto f(F f) 
    -> decltype(true? f() : void()) 
{ 
    f(); 
} 

template <class F> 
auto f(F f) -> decltype(int(f())) 
{ 
    f(); 
    return 42; 
} 

int main(){ 
    f([]{}); 
} 

Not. Clang 3.1 doğru

f([]{ return 42; }); 
İlgili konular