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 &¶m : params)
{
std::invoke(func, param);
}
}