Sentinel based find with conditional fallback to std::find
std::integral_constant&lt;bool, std::is_nothrow_copy_assignable&lt;std::remove_reference_t&lt;decltype(*first)&gt; &gt;::value&gt;


is a very complicated synonym for

std::is_nothrow_copy_assignable_t&lt;std::remove_reference_t&lt;decltype(*first)&gt;&gt;


in this context, because all the UnaryTypeTraits are defined by the standard to be "publicly and unambiguously derived" (directly or indirectly) from their BaseCharacteristic of std::true_type or std::false_type.



Your code returns std::prev(last) when *last == value, even if there's an instance of value prior to that in the sequence. This isn't a bug (presumably), but it's surprising enough that you should probably document it explicitly somewhere; otherwise I'd assume a function named find to have semantics exactly the same as std::find [alg.find] — i.e., "return an iterator to the first matching element".



Checking is_nothrow_copy_assignable&lt;...&gt; doesn't really buy you anything, if you aren't going to check is_nothrow_copy_constructible&lt;...&gt; and is_nothrow_equality_comparable&lt;...&gt; and is_nothrow_prefix_incrementable&lt;...&gt;... and so on, for all the other operations you do inside the "critical section" of your function (between the line where you blow away the old value of *real_last and the line where you restore it).

Alternatively, you could use a try/catch to make sure that you always restore the old value of *real_last. Since C++ lacks the "finally" construct that exists in languages such as Java and Python, I recommend a generic scope-guard construct such as Auto() if you find yourself doing this kind of thing very often.



Your code has a problem with empty ranges.