使用 auto Return 个不同的 Lambda

Using auto to Return Different Lambdas

所以我很好奇 gives me the flexibility to do this. I have this answer 是否包含代码:

template <typename T>
function<void(vector<pair<T, T>>&)> vertex_triangle(const size_t index, const vector<pair<T, T>>& polygon) {
    if (0U == index){
        return [&](vector<pair<T, T>>& output){ output.push_back(polygon.back());
                                                output.push_back(polygon.front());
                                                output.push_back(polygon[1U]); };
    }else if (index == (polygon.size() - 1U)){
        return [&](vector<pair<T, T>>& output){ output.push_back(polygon[polygon.size() - 2U]);
                                                output.push_back(polygon.back());
                                                output.push_back(polygon.front()); };
    }else{
        return [&](vector<pair<T, T>>& output){ output.push_back(polygon[index - 1U]);
                                                output.push_back(polygon[index]);
                                                output.push_back(polygon[index + 1U]); };
    }
}

我认为我应该能够将函数签名更改为:auto vertex_triangle(const size_t index, const vector<pair<T, T>>& polygon) 从而保留闭包类型优化。另外,我真的很想让我的 lambda 参数是 auto& 而不是 vector<pair<T, T>>&.
会支持这些更改吗?

Would support these changes?

没有。您要求的是具有 returns 不同类型的函数,具体取决于 运行时条件 。唯一的方法是类型擦除——无论是 std::function 类型还是标准 OOP 继承类型。

如果您可以将条件提升为常量表达式,那么您可以使用 if constexpr(或简单地标记分派)来完成此操作。但考虑到第二种情况是 index == vector.size() - 1,我猜这是不可能的。


也就是说,你真的需要不同的功能吗?为什么不(注意:通过复制捕获 index 以避免悬挂引用):

template <typename T>
auto vertex_triangle(const size_t index, const vector<pair<T, T>>& polygon) {
    return [&polygon, index](vector<pair<T, T>>& output){ 
        size_t lo = index == 0 ? polygon.size() - 1 : index - 1;
        size_t hi = index == polygon.size() - 1 ? 0 : index + 1;

        for (size_t offset : {lo, index, hi}) {       
            output.push_back(polygon[offset]);
        }
    };
}

不,函数的 return 类型不能基于非模板值函数参数而变化。

你可以这样写一个变体工厂:

template<class F, class T, T t, T...ts>
auto variant_from(
  F&& f,
  std::integral_constant<T, t> which,
  std::integer_sequence<T, ts...>
) ->
std::variant< std::decay_t<
  std::result_of_t< F&&( std::integral_constant<T, t>)>
>... > {
  return std::forward<F>(f)( which );
}

使用它我们可以 return lambda 的变体,这与您所能得到的差不多。

template <typename T>
auto vertex_triangle(const size_t index, const vector<pair<T, T>>& polygon) {
  auto choice_list = std::make_index_sequence<3>{};
  auto algorithm = [&polygon, index](auto choice) {
    if constexpr (choice==0){
      return [&polygon](vector<pair<T, T>>& output){ 
        output.push_back(polygon.back());
        output.push_back(polygon.front());    
        output.push_back(polygon[1U]);
      };
    }else if constexpr (choice == 1){
      return [&polygon](vector<pair<T, T>>& output){
        output.push_back(polygon[polygon.size() - 2U]);
        output.push_back(polygon.back());
        output.push_back(polygon.front());
      };
    }else{
      return [&polygon, index](vector<pair<T, T>>& output){
        output.push_back(polygon[index - 1U]);
        output.push_back(polygon[index]);
        output.push_back(polygon[index + 1U]); };
      }
    };
  if (index == 0)
    return variant_from( algorithm, std::integral_constant<std::size_t, 0>{}, choice_list );
  else if (index == output.size()-1)
    return variant_from( algorithm, std::integral_constant<std::size_t, 1>{}, choice_list );
  else
    return variant_from( algorithm, std::integral_constant<std::size_t, 2>{}, choice_list );
}

我确定可以稍微清理一下。

variant_from 使用算法推导出什么变体是一个总和类型,然后只将其中一个存储在 returned 变体中。我们在具有相同 return 类型但存储不同值的 3 个不同上下文中调用它。

请注意 variant 上的 operator() 没有达到我们想要的效果,但我们可以对其进行扩充。