5

我正在尝试提供一个调用提供的 lambda 的函数,我想知道如果该函数具有 return type ,是否可以让它返回一个默认值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返回类型,然后说是否匹配intor的void版本是模棱两可的f,这有点愚蠢。

这样做的一个原因是,如果函数f需要一个返回值,但用户提供了一个不包含return语句的 lambda,编译器会推断出一个void类型,然后会出错。因为在实际场景中,我很清楚当用户不想提供一个合理的默认返回值时,我想知道是否有可能让编译器允许用户忽略经常不必要的return语句方便。

谢谢。我应该提到我正在使用 GCC 4.6.3。

:根据 Xeo 的 using 建议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();
}

谢谢!

4

2 回答 2

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第二个。这应该让你的代码工作。我还没有测试它,所以我不确定它是否完全有效。

于 2012-09-22T19:45:57.680 回答
2

给我一个为什么编译器应该能够根据您在函数中执行的操作来推断为什么要选择哪个重载的原因?在 C++ 中,仅当每个参数都可与参数匹配时,才关注重载解析。函数的返回类型和内容与what-so-ever无关。

正如 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 退出。Clang 3.1 正确地使

f([]{});

工作,以及

f([]{ return 42; });
于 2012-09-22T21:17:57.050 回答