Here is the abomination:
template <typename BidirIt, typename OutputIt, typename T,
typename BinaryDoOp, typename BinaryUndoOp>
void sliding_window(BidirIt first, BidirIt last, OutputIt d_first,
typename std::iterator_traits<BidirIt>::difference_type length,
T init = typename std::iterator_traits<BidirIt>::value_type(),
BinaryDoOp op = std::plus<>{},
BinaryUndoOp undo = std::minus<>{})
So I want T
to be std::iterator_traits<BidirIt>::value_type
by default and default construct an object of that type giving it a name init
.
After solving a problem of fitting some of the variable types in one line, I found that compiler is not able to deduce T
, here is what it exactly says:
error: no matching function for call to 'sliding_window' sliding_window(v.begin(), v.end(), output.begin(), window_length/, 0, std::plus<>(), std::minus<>()/);
note: candidate template ignored: couldn't infer template argument 'T' void sliding_window(BidirIt first, BidirIt last, OutputIt d_first,
My compiler is clang++-3.9.
Call site code:
std::vector<int> v(window_length + window_count - 1);
std::iota(v.begin(), v.end(), 0);
std::vector<int> output(window_count);
std::vector<int> correct_result{3, 6, 9, 12};
sliding_window(v.begin(), v.end(), output.begin(), window_length/*, 0, std::plus<>(), std::minus<>()*/);
When the commented part is uncommented code works correctly.
From what I know about templates, it should be able to deduce that type since it is practically a default constructor call there, which should yield std::iterator_traits<BidirIt>::value_type
. Do I have any misunderstanding of how type of default arguments work when function is templated on a type?
Question: how to fix it? It would be great to add some explanations to it too.
Template types cannot be deduced from defaulted templated arguments: C++14 lambda's default argument type deduction depending on preceding arguments. As far as how to fix it, you would need to default the types:
template <typename BidirIt, typename OutputIt,
typename T = typename std::iterator_traits<BiDirIt>::value_type,
typename BinaryDoOp = std::plus<>,
typename BinaryUndoOp = std::minus<>>
void sliding_window(BidirIt first, BidirIt last, OutputIt d_first,
typename std::iterator_traits<BidirIt>::difference_type length,
T init = T{},
BinaryDoOp op = BinaryDoOp{},
BinaryUndoOp undo = BinaryUndoOp{})
Another approach would also be to have overloaded functions, where the ones with fewer template parameters/arguments call the ones with more and handle the defaulting at the call site. This is the approach used by std::accumulate
: http://en.cppreference.com/w/cpp/algorithm/accumulate. Then you'd have multiple functions so there's some repetition there, but each one is quite a bit more readable.