Max element of input iterator range
Don't use a lambda

This code:

std::for_each(first, last, [&amp;result, comp] (ValueType curr) {
    if (comp(result, curr)) result = std::move(curr);
});


is just a lot messier than the non-lambda equivalent:

for (; first != last; ++first) {
    ValueType cur = *first;
    if (comp(result, cur)) {
        result = std::move(cur);
    }
}


I don't see the advantage in the lambda. 

Avoid the copy

Once you advance an input iterator, all earlier iterators are invalidated. But you can dereference the same one multiple times. In this case, you're incurring an unnecessary copy of ValueType, you can just write:

for (; first != last; ++first) {
    if (comp(result, *first)) {
        result = std::move(*first);
    }
}


Move iterators

Dereference likely returns a const T&amp; - so you probably want to wrap the iterators in std::make_move_iterator first. That will actually let you move-from the iterator, instead of looking like you're moving from and actually copying from. 

advance is excessive

You can just write:

ValueType result{*first++};


Or:

ValueType result{*first};
++first;


There's no need for advance() - you know operator++ is supported. 

Throwing on empty range

Honestly, I'd prefer it just be undefined behavior and avoid the first check. Let the user deal with it. That's just a personal preference though. 

Additionally, you could return an optional&lt;ValueType&gt;, returning none if the range is empty. 

Defer to std::max_element?

Since std::max_element is more efficient than yours for forward iterators, it'd be nice to defer to it if you're given a forward iterator:

template &lt;class It, class Cmp&gt;
typename std::iterator_traits&lt;It&gt;::value_type
max_input(It first, It last, Cmp mp) {
    // possibly check empty range and throw here, if that's what you want
    return max_input(first, last, cmp, typename std::iterator_traits&lt;It&gt;::iterator_category{});
}

template &lt;class It, class Cmp&gt;
typename std::iterator_traits&lt;It&gt;::value_type
max_input(It first, It last, Cmp cmp, std::input_iterator_tag) {
    /* your implementation */
}

template &lt;class It, class Cmp&gt;
typename std::iterator_traits&lt;It&gt;::value_type
max_input(It first, It last, Cmp cmp, std::forward_iterator_tag) {
    return *std::max_element(it, last, cmp);
}


Excessive commenting

Avoid this sort of commenting style:

#include &lt;iterator&gt;   // std::iterator_traits, std::advance
#include &lt;stdexcept&gt;  // std::logic_error
#include &lt;algorithm&gt;  // std::for_each
#include &lt;functional&gt; // std::less
#include &lt;utility&gt;    // std::move


It's just verbose and provides no value.