有没有办法在C++11中匹配返回值

Any way to match on return value in C++11?

本文关键字:返回值 C++11 有没有      更新时间:2023-10-16

我正试图提供一个调用所提供lambda的函数,我想知道如果该函数的返回类型为void,是否可以让它返回默认值。

到目前为止,我有一个函数,它返回lambda的返回值,但如果lambda是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需要一个返回值,但用户提供的lambda不包括return语句,则编译器会推断出void类型,并出错。由于在实际场景中,当用户不愿意提供合理的默认返回值时,我很清楚应该是什么,所以我想知道是否可以让编译器允许用户为了方便而忽略通常不必要的return语句。

谢谢。我应该提到,我使用的是GCC 4.6.3。

答案:根据Xeo关于使用enable_if的建议,我提出了以下建议,似乎有效:

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

谢谢!

您可以使用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。这应该能让你的代码正常工作。我还没有测试过,所以我不确定它是否完全有效。

给我一个理由,说明为什么编译器应该能够根据函数内部的操作来推断为什么要选择哪个重载?在C++中,只有当每个参数都与一个参数匹配时,才考虑重载解析。函数的返回类型和内容无关紧要。

正如STL所说:

TLDR:模板是贪婪的!除非你完全确定会发生什么,否则不要让它们超载。

作为参数的通用引用(template<class T> void f(T&&);)是你能得到的最贪婪的引用。

你可以像@JKor用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([]{});
}

注意,GCC 4.7有一个错误,decltype(int(void_returning_function()))不会导致函数SFINAE out。Clang 3.1正确制作

f([]{});

工作,以及

f([]{ return 42; });