繁体   English   中英

我可以让返回类型 auto 与具有相同签名但不同捕获的 lambda 一起使用吗?

[英]Can I get return type auto to work with lambdas of the same signature but different captures?

我正在尝试使用 auto 作为返回的 lambda function 的返回类型。 这是一个最小的示例,它演示了我遇到的问题:

#include <iostream>
#include <memory>

auto
get_func()
{
    auto i = std::make_unique<int>(2);
    if (*i == 1) {
        return [i=std::move(i)]() {
            return *i;
        };
    }
    return [](){ return 2; };
}

int
main(int argc, char* argv[])
{
    auto func = get_func();
    std::cout << "val: " << func() << std::endl;
    return 0;
}

在我的 Mac 上,我收到以下编译错误:

$ g++ -g -Wall -Werror -std=c++17 test.cc -o test
test.cc:13:5: error: 'auto' in return type deduced as '(lambda at test.cc:13:12)' here but deduced as '(lambda at test.cc:9:16)' in earlier return statement
    return [](){ return 2; };
    ^
1 error generated.

对,它们都被推断为lambda 而且它们都具有相同的void(void)签名。 我看到问题是因为它们指定了不同的捕获吗? 如果是这样,我有什么选择来获得相同的 function 调用以使调用者工作(如main中的cout调用中所示)。

我看到问题是因为它们指定了不同的捕获吗?

即使它们完全一样,你也会看到一个问题,一个令牌一个令牌。

每个 lambda 表达式创建一个唯一的闭包类型,它不同于任何其他 lambda 创建的任何闭包类型。 无法调和这种差异,因此auto扣除无法成功。

如果您打算返回两个不同的 lambda(使用std::function或支持仅移动语义的自定义类型),则需要键入擦除实际函子。 那,或者可能将整个逻辑卷到一个 lambda 中:

auto
get_func()
{
    auto i = std::make_unique<int>(2);
    return [i=std::move(i)]() {
        if (*i == 1) {
            return *i;
        }
        return 2;
    };
}

而且它们都具有相同的void(void)签名。

虽然 lambda 具有相同的operator()签名,但它们不是相同的 class 类型。 它们是具有不同类型的不同对象。 自动返回类型推导要求所有返回语句具有相同的类型,而您在这里没有。

在这种情况下,您有不同的类型,您需要一个共同的返回类型。 您可以使用std::function获得它,因为它允许您通过operator()类型而不是 lambda 类型返回。 那给你

std::function<void(void)> get_func()
{
    auto i = std::make_unique<int>(2);
    if (*i == 1) {
        return [i=std::move(i)]() {
            return *i;
        };
    }
    return [](){ return 2; };
}

我认为最好的变体(预示双关语)是 StoryTeller 将逻辑放入单个 lambda 的解决方案。

为了好玩,作为替代方案,您可以使用一个变体来固定您的 lambda。 您可以围绕它创建一个简单的包装器:

template <class... Fs>
struct Lambda_fixed_variant
{
    std::variant<Fs...> f_;

    template <class L>
        // requires std::is_constructible_v<decltype(f_), std::in_place_type_t<L>, L&&>
    Lambda_fixed_variant(L l)
        : f_{std::in_place_type_t<L>{}, std::move(l)}
    {}

    template <class... Args>
    auto operator()(Args&&... args) const
    {
        return std::visit([&] (const auto& l) {
                return l(std::forward<Args>(args)...);
            },
            f_
            );
    }
};

auto get_func()
{
    auto i = std::make_unique<int>(2);

    auto l1 = [i=std::move(i)]() { return *i; };
    auto l2 = [](){ return 2; };

    using L1 = decltype(l1);
    using L2 = decltype(l2);

    if (true)
    {
        return Lambda_fixed_variant<L1, L2>{std::move(l1)};
    }
    return Lambda_fixed_variant<L1, L2>{l2};
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM