Search code examples
c++templateslambdarangestd

How to overload functions defined with lambda syntax for specific concepts (requirements)?


I need overloading of the lambda for specific concepts (requirements). It works just fine in template syntax, but of course "lambda is not a function" and can't be overloaded.

Unfortunately, solutions provided in the aforementioned Overload a lambda function don't help, because:

  1. My question is about concepts/requirements, not about types (key difference here).
  2. In overall case I my have many different concepts and hack with if constexpr std::is_same_v becomes quite fragile; one new concept added and I will have to find and update all client code which is not possible.

The question is, if I stay with with lambda function syntax, what could I do to use the same name for different concepts (requirements), as below?

#include <ranges>
#include <vector>

template <std::ranges::input_range Rng>
void fn_template(Rng& data) {
};

template <std::ranges::random_access_range Rng>
void fn_template(Rng& data) {
};

constexpr auto lambda = []<std::ranges::input_range Rng>(Rng & data) {
};

// Redefinition error, of course
constexpr auto lambda = []<std::ranges::random_access_range Rng>(Rng & data) {
};

int main()
{
    std::vector<float> v = { 0.0f, 1.0f, 0.0f, 2.0f };

    auto no_zeros = v | std::views::filter([](const auto& lhs) { return lhs != 0.0f; });

    // Works just fine
    fn_template(v);
    fn_template(no_zeros);

    // Can't achieve
    lambda(v);
    lambda(no_zeros);
}

Demo


Solution

  • You can use the overloaded trick, which combines multiple lambdas into a single overload set (Demo).

    template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
    template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
    
    constexpr auto lambda = overloaded(
        []<std::ranges::input_range Rng>(Rng & data) {
        },
        []<std::ranges::random_access_range Rng>(Rng & data) {
        }
    );