Home > Software design >  Pass parameterized function and list of parameters using c 20 Concepts
Pass parameterized function and list of parameters using c 20 Concepts

Time:03-07

I have a function foo that take one parameter of any type like this:

void foo(int& x)
{
    x = 4;
}

Now i want to create a templated function bar that takes a function with 1 parameter and a list of parameters to call the function with.

template<typename Func, typename Params>
void bar(Func func, Params params)
{
     for(auto param : params)
     {
         func(param);
     }
}

This works and compiles, but I want to improve this to use C 20 concepts. First I created an iterable concept like this:

template<typename Container, typename ElementType>
concept iterable = std::ranges::range<Container> && std::same_as<typename std::iterator_traits<Container>::value_type, ElementType>;

and used it to check if the value_type of the iterator is the same as the parameter type of the provided container like this:

template<typename Func, typename ParamType, typename Params>
requires std::invocable<Func, ParamType> && iterable<Params, ParamType>
void bar(Func func, Params params)
{
     for(auto param : params)
     {
         func(param);
     }
}

But this doesn't compile for this simple example

std::vector<int> payload(10, 5);
bar(&foo, payload);

with the following error message

error C2672: 'bar': no matching overloaded function found
error C2783: 'void bar(Func,Params)': could not deduce template argument for 'ParamType'

Which somewhat makes sense as Func and Params are arguments of the function and ParamType is not, but I want to solve this without having to manually specify the type of parameter. I also tried changing the signature to void bar(Func func, Params<ParamType> params) or change to template to ... typename ParamType, typename Params<ParamType>> both of which didn't compile.

How can I solve this without explicitly specifying the parameter type to bar?

CodePudding user response:

You solve this by using the tools the standard library gives you. You use theinput_range and the invocable concepts, providing the range_reference_t type of the given range as the parameter to the invoked function.

template<typename Func, std::ranges::input_range Rng>
  requires std::invocable<Func, std::ranges::range_reference_t<Rng>>
void bar(Func func, Rng params)
{
     for(auto &&param : params)
     {
         std::invoke(func, param);
     }
}
  • Related