所以我很好奇c++17是否给了我这样做的灵活性。我有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>>&
。
c++17会支持这些更改吗?
答案 0 :(得分:9)
c++17会支持这些更改吗?
没有。您要求的是具有根据运行时条件返回不同类型的函数。唯一的方法是删除类型 - 无论是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]);
}
};
}
答案 1 :(得分:1)
不,函数的返回类型不能基于非模板值函数参数而变化。
你可以写一个像这样的变种工厂:
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 );
}
使用这个我们可以在lambdas上返回一个变体,它尽可能接近你。
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
使用该算法推导出变量是和类型的内容,然后只将其中一个存储在返回的变量中。我们在3个不同的上下文中调用它,它们具有相同的返回类型,但存储了不同的值。
请注意operator()
上的variant
并没有做我们想要的事情,但我们可以对其进行补充。