Search code examples
c++lambdaclosuresc++17auto

Using auto to Return Different Lambdas


So I'm curious if gives me the flexibility to do this. I have this answer which contains the code:

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]); };
    }
}

I think that I should be able to change the function signature to: auto vertex_triangle(const size_t index, const vector<pair<T, T>>& polygon) thereby preserving closure type optimization. Additionally I'd really like to have my lambda parameter be auto& rather than vector<pair<T, T>>&.
Would support these changes?


Solution

  • Would support these changes?

    No. What you're asking for is to have a function that returns different types depending on a runtime condition. The only way to do that is type erasure - whether of the std::function kind or the standard OOP inheritance kind.

    If you could lift the conditions to constant expressions, then you could accomplish this with if constexpr (or simply tag dispatching). But given that the second case is index == vector.size() - 1, I'm guessing this isn't possible.


    That said, do you actually need different functions? Why not (NB: capture index by copy to avoid dangling reference):

    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]);
            }
        };
    }