Search code examples
c++templatesc++14c++17initializer-list

template function that deduces both containers and initializer_list-s


I'd like to write a helper function like:

template <typename F, typename Range1, typename Range2>
auto helper(const Range1& left, const Range2& right, F&& pred)
{
    using namespace std; // for cbegin/cend and ADL
    return pred(cbegin(left), cend(left), cbegin(right), cend(right));
}

It works well for containers:

std::vector<int> v1 = {1,2,3,4,5,6};
std::vector<int> v2 = {5,4,3,2,1,6};

std::cout << helper(v1, v2, [](const auto&... args){ return std::is_permutation(args...);}) << std::endl;

but it fails to deduce initializer_list-s (example):

std::cout << helper({1,2,3,4,5,6}, {5,4,3,2,1,6}, [](const auto&... args){ return std::is_permutation(args...);}) << std::endl;

Is there an idiomatic way to rewrite helper so that it deduces both containers and initializer_list-s?

I can't come up with anything better than overloads for all combinations of container and initializer_list.


Solution

  • I think the fundamental problem here is that a braced-init-list like { 1, 2, 3 } is just an initializer and not an object of type std::initializer_list<T>. It can potentially be used to initialize an object of some given type. But it's not an object of any type itself. And there doesn't seem to be anything in the rules for function template argument deduction that would allow you to get an std::initializer_list<T> from a braced-init-list argument unless your function parameter was already declared to be some sort of std::initializer_list<T> to begin with.

    So I'm afraid writing those overloads will be the simplest solution…