如何正确地找出lambda表达式的返回类型

4

基本上如何使以下代码编译通过?

我知道它失败了,因为编译器试图评估类似于([](int &i){})(0)的东西,但如何解决这个问题呢?

template <class TElement>
struct foo {
    TElement _e;
    foo(TElement e) : _e(e){}
    template <class Lambda>
    void bar(Lambda f) {
        using TResult = decltype(std::declval<Lambda>()(std::declval<TElement>()));
    }
};

int main() {

    foo<int>(0).bar([](int i){}); // compile
    foo<int>(0).bar([](int &&i){}); // compile
    foo<int>(0).bar([](int const &i){}); // compile
    foo<int>(0).bar([](int &i){}); // failed

}

你可以使用 foo<int&>(i).bar([](int &i){}); - Jarod42
@Jarod42 这将使“_e”成员具有引用类型,这可能不是所期望的。 - jrok
@jrok 但是 foo<int&>(0) 不会编译。 - Bryan Chen
1
Lambda函数并不特殊。您可以通过与其他可调用对象相同的方式来确定lambda函数的返回类型。 - R. Martinho Fernandes
3个回答

7
您可以使用以下特性:
template <typename T>
struct return_type : return_type<decltype(&T::operator())>
{};
// For generic types, directly use the result of the signature of its 'operator()'

template <typename ClassType, typename ReturnType, typename... Args>
struct return_type<ReturnType(ClassType::*)(Args...) const>
{
    using type = ReturnType;
};

4

有两种方法。首先:

using TResult = decltype(f(_e));

第二个选项是:
using TResult = typename std::result_of<Lambda&(TElement&)>::type;

您的代码暗示TElement是一个临时/右值。上面的&将它们变成了左值。

我不认为有必要使用 std::declval<Lambda>。因为已经有了 f - jrok
而且使用第一种方式,foo<int>(0).bar([](int &&i){}); 无法编译。 - jrok
@jrok 如果 OP 要传递 f 成员变量,那么它在那里也无法编译。由于他们希望 lambda 接受 int& 工作,我认为这是情况。这表明还有另一个改进... - Yakk - Adam Nevraumont

2
您可以通过以下方式解决这个问题:
template <typename Lambda, typename T>
struct lambda_return_type {
    private:
    template<typename U>
    static constexpr auto check(U*) -> decltype(std::declval<Lambda>()(std::declval<U>()));

    template<typename U>
    static constexpr auto check(...) -> decltype(std::declval<Lambda>()(std::declval<U&>()));

    public:
    typedef decltype(check<T>(nullptr)) type;
};

并且

void bar(Lambda f) {
    typedef typename lambda_return_type<Lambda, TElement>::type TResult;
}

为什么要使用 *(U*)nullptr 而不是 std::declval<U&>() - Yakk - Adam Nevraumont
@Yakk 谢谢 - 这是一个 declval,现在 - user2249683

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接