I have a function which accepts arbitrary iterable objects/containers:
auto iterate(auto&& iterable);
And it operates on them using range-based for-loops in a generic manner.
This works fine with standard containers, C-style arrays, and std::generator
, but it fails when I try to pass it an init-list:
iterate({1, 2, 3});
I get the error error: no matching function for call to ‘iterate(<brace-enclosed initializer list>)
and couldn’t deduce template parameter ‘auto:57’
.
How can I include initalizer lists in the considered candidates for deduction without writing a separate overload? I need it to be only one function because I also want to write iterator-based utilities that operate on multiple iterables, and I don't know how to write functions that would operate on all of them easily if I had to write multiple functions for each combination of ordinary iterable and init-list.
I have a function which accepts arbitrary iterable objects/containers:
auto iterate(auto&& iterable);
And it operates on them using range-based for-loops in a generic manner.
This works fine with standard containers, C-style arrays, and std::generator
, but it fails when I try to pass it an init-list:
iterate({1, 2, 3});
I get the error error: no matching function for call to ‘iterate(<brace-enclosed initializer list>)
and couldn’t deduce template parameter ‘auto:57’
.
How can I include initalizer lists in the considered candidates for deduction without writing a separate overload? I need it to be only one function because I also want to write iterator-based utilities that operate on multiple iterables, and I don't know how to write functions that would operate on all of them easily if I had to write multiple functions for each combination of ordinary iterable and init-list.
Share Improve this question asked Feb 17 at 22:32 HeliumHydrideHeliumHydride 811 silver badge5 bronze badges 6 | Show 1 more comment1 Answer
Reset to default 0I know you want to avoid an overload, but since you are using C++20 or later, your best option looks to be to add one that delegates to your existing function by passing it a std::span
, like so:
template <class T> auto iterate
(std::initializer_list <T> il)
{
std::span s {il.begin (), il.end ()};
return iterate (s);
}
A span
is cheap to construct (might even be free, in this situation), but maybe adding an overload adds too much boilerplate, we don't have enough context to know.
<brace-enclosed initializer list>
is a great hint that{1, 2, 3}
has no type. Hence,couldn’t deduce template parameter
. You should overloaditerate
forstd::initializer_list<auto>
. – 3CxEZiVlQ Commented Feb 17 at 22:36std::initializer_list
automatically. – HeliumHydride Commented Feb 17 at 22:42initializer_list
) then you need to help the compiler by creating a suitable container at the call point. For example,iterate(std::vector<int>{1,2,3})
. Probably simpler (and less expensive) to create an overload (templated if necessary) that accepts a suitableinitializer_list
. – Peter Commented Feb 18 at 4:17iterate(std::array{1,2,3})
. It should roughly be as expensive as an std::initializer_list – ThePirate42 Commented yesterday