2012-09-22 4 views
5

나는 제공된 람다를 호출하는 함수를 제공하려고 노력하고 있으며 함수에 반환 유형이 void 인 경우이 함수가 기본값을 반환 할 수 있는지 궁금합니다. 여기 C++ 11에서 반환 값을 비교하는 방법은 무엇입니까?

내가 지금까지 람다의 반환 값을 반환하는 기능을 가지고 있지만, 람다가 void 경우, 다음은 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; 
} 

이이 오류가 발생 반환 무엇

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

분명히 이것은 C++이 반환 유형에 따라 다형성을 사용할 수 없기 때문입니다. 그러나 좋은 C++ 11 트릭이 있는지 궁금합니다. decltype 또는 일부 템플릿 마법을 사용하는 것이 좋을 수도 있습니다. 컴파일러는 void 반환 유형을 유추하고 int 또는 void 버전을 f과 일치 시킬지 모르는 것을 말합니다. 이는 다소 바보입니다.

이 일을하는 이유는 기능 f는 반환 값을 기대하지만, 사용자가 return 문을 포함하지 않는 람다를 제공하는 경우, 컴파일러가 void 유형을 유추하고, 오류가 밖으로 것입니다. 실제 시나리오에서는 합리적인 기본 반환 값이 사용자가 하나를 제공하지 않을 때 어떤 값을 가져야하는지에 대한 좋은 생각을 가지고 있기 때문에 사용자가 자주 불필요한 return 문을 무시하도록 컴파일러를 사용할 수 있는지 궁금합니다. 편의상.

감사합니다. GCC 4.6.3을 사용하고 있음을 언급해야합니다.

대답 :

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(); 
} 

감사 : enable_if를 사용 Xeo의 제안에 따라, 나는 작동하는 것 같다 다음, 함께 왔어요!

+0

당신이 정상적인 기능에 F를 테스트 한 같은 aswell

f([]{}); 

작업을하게? – CharlesB

+0

예, 일반적인 기능에서는 모호합니다. – Steve

+0

'decltype'의 두 번째 매개 변수 : 그것이 무엇인지 물어볼 수 있습니까? (정말로, 내가 모르기 때문에!). – 0x499602D2

답변

3

std :: enable_if를 사용할 수 있습니다.

반환 유형은 첫 번째 경우는 std::enable_if<!std::is_same<decltype(h()), void>::value, decltype(h())>:type이고 두 번째 경우에는 std::enable_if<std::is_same<decltype(h()), void>::value, int>::type이됩니다. 그게 당신의 코드를 작동시켜야합니다. 나는 그것을 테스트하지 않았으므로 완전히 작동하는지 확신 할 수 없다.

+0

"모호한"오류가 여전히 반환됩니다. – Steve

+0

@ 스티브 : 아니오, 올바르게 작동합니다. 어딘가에 오타가있을 수 있습니다. [this] (http://liveworkspace.org/code/e0c94a11d120300743e202f4daec8a66)를 참조하십시오. – Xeo

+0

@Xeo : 아, 감사합니다. JKor 솔루션의 첫 번째 부분에있는 두 번째'decltype (h())는'f() '의 반환 값을 변경하기 때문에 문제가 있다고 생각합니다. 나는 당신의 예제를 기반으로 작동하도록했습니다, 나는 질문에 코드를 게시 할 것입니다. – Steve

2

컴파일러가 왜 함수 내부에서 무엇을 기반으로 선택해야하는지 과부하를 유추 할 수있는 이유에 대해 설명해주십시오. C++에서 모든 인수가 매개 변수와 일치 할 수있는 경우에만 과부하 해결이 필요합니다. 리턴 타입과 함수의 내용은 아무런 의미가 없습니다. what-so-ever.

As STL says :

TLDR : 템플릿 욕심! 일어날 일이 절대 확실하지 않으면 과부하 상태가되지 않도록하십시오.

그리고 범용 참조 (template<class T> void f(T&&);)는 얻을 수있는 가장 탐욕스러운 것입니다.

당신은 @JKor이 SFINAE로 말한다처럼 그것을 해결하지만, 단순화 할 수 있습니다 GCC 4.7 decltype(int(void_returning_function())) 함수 밖으로 SFINAE 발생하지 않는 버그가 있음을

#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([]{}); 
} 

참고. 연타 3.1 올바르게

f([]{ return 42; }); 
관련 문제