Sorry for the vague title, but I couldn't come up with a better one.
I wrote a function to flatten containers:
template <typename Container, typename OutIt> void flatten(const Container& container, OutIt res) { if constexpr (std::is_convertible_v<typename Container::value_type, typename std::iterator_traits<OutIt>::value_type>) { for (const auto& value : container) { *res = value; ++res; } } else { for (const auto& subContainer : container) flatten(subContainer, res); } } And I wanted it to be used like:
vector<vector<int>> test = {{1}, {2, 3, 4}, {5, 6}, {7}}; vector<int> res; flatten(test, std::back_inserter(res)); This should basically copy all the nested values from test to res, so that res == { 1, 2, 3, 4, 5, 6, 7 }.
However, if I want to compile the code, the compiler throws some errors which basically say, that the code in the else branch gets compiled instead of the if constexpr block.
I.e. The first instantiation is void flatten<vector<vector<int>>, OutIt>() which is correct. The second instantiation (which is triggered by the else block) is void flatten<vector<int>, OutIt>() which is also correct. But for the 2nd instantiation, the if constexpr expression should evaluate to true, as vector<int>::value_type is int and std::iterator_traits<OutIt>::value_type> is also int. But somehow the compiler tries to instantiate a third template void flatten<int, OutIt>() which causes the compiler errors (because I try to iterate over an integer).
Why does the compiler instantiate the 3rd template?