为什么不能在函数中使用范围?

Why can't ranges be used if in a function?

我正在尝试获得 range 如下所示 python:

#include <iostream>
#include <ranges>

auto Range(double start, double end, double step)
{
    if (start <= end) {
        auto step_fun = [=](auto x) { return x * step + start; };
        auto end_pred = [=](auto x) { return x <= end; };
        auto range =
            std::views::iota(0)
            | std::views::transform(step_fun)
            | std::views::take_while(end_pred);
        return range;
    }
    else {
        auto step_fun = [=](auto x) { return -x * step + start; };
        auto end_pred = [=](auto x) { return x >= end; };
        auto range =
            std::views::iota(0)
            | std::views::transform(step_fun)
            | std::views::take_while(end_pred);
        return range;
    }
}
int main() {
    auto range = Range(108, 100, 1);

    for (auto i : range)
        std::cout << i << ' ';
    return 0;
}

但是 Visual Studio 告诉我:

Error   C3487   'std::ranges::take_while_view<std::ranges::transform_view<std::ranges::iota_view<_Ty,std::unreachable_sentinel_t>,Range::<lambda_3>>,Range::<lambda_4>>': all return expressions must deduce to the same type: previously it was 'std::ranges::take_while_view<std::ranges::transform_view<std::ranges::iota_view<_Ty,std::unreachable_sentinel_t>,Range::<lambda_1>>,Range::<lambda_2>>'   

Message     No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called    test    

但只有start>endstart<end,它可以工作,如:

auto Range(double start, double end, double step)
{
auto step_fun = [=](auto x) { return x * step + start; };
        auto end_pred = [=](auto x) { return x <= end; };
        auto range =
            std::views::iota(0)
            | std::views::transform(step_fun)
            | std::views::take_while(end_pred);
        return range;
}

我该如何解决?

一个函数必须有一个 return 类型,auto 不会改变这一点。你的两个 return 有不同的、不兼容的类型,因为每个 lambda 表达式都有一个唯一的类型。

错误消息宁愿掩埋它:blah blah Range::<lambda_3>,Range::<lambda_4> vs blah blah Range::<lambda_1>,Range::<lambda_2>

你可以做一些算术将它减少到一个 return

auto Range(double start, double end, double step)
{
    if (start > end) {
        step *= -1;
    }
    int count = (end - start) / step;

    auto step_fun = [=](auto x) { return x * step + start; };
    return std::views::iota(0, count)
         | std::views::transform(step_fun);
}

警告:如果 step 为负数,此函数仍然存在问题,如果 end 无法从 start.

访问,您可能想要抛出

因为take_whiletransform的结果类型包含函数类型作为签名的一部分,但一个函数只能有一个return类型。

除了已经回答的,你还可以删除类型。

#include <iostream>
#include <ranges>
#include <functional>

auto Range(double start, double end, double step)
{
    std::function<double(double)> step_fun;
    std::function<double(double)> end_pred;

    if (start <= end) {
        step_fun = [=](auto x) { return x * step + start; };
        end_pred = [=](auto x) { return x <= end; };
    }
    else {
        step_fun = [=](auto x) { return -x * step + start; };
        end_pred = [=](auto x) { return x >= end; };    
    }
    auto range =
            std::views::iota(0)
            | std::views::transform(step_fun)
            | std::views::take_while(end_pred);
    return range;
}
int main() {
    auto range = Range(108, 100, 1);

    for (auto i : range)
        std::cout << i << ' ';
    return 0;
}