<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Mon, Mar 10, 2014 at 12:12 PM, Arthur O'Dwyer <span dir="ltr"><<a href="mailto:arthur.j.odwyer@gmail.com" target="_blank">arthur.j.odwyer@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class="">On Sun, Mar 9, 2014 at 9:32 PM, David Blaikie <<a href="mailto:dblaikie@gmail.com">dblaikie@gmail.com</a>> wrote:<br>

> On Mar 9, 2014 6:57 PM, "Richard Smith" <<a href="mailto:richard@metafoo.co.uk">richard@metafoo.co.uk</a>> wrote:<br>
>> On Sun, Mar 9, 2014 at 6:37 PM, Arthur O'Dwyer <<a href="mailto:arthur.j.odwyer@gmail.com">arthur.j.odwyer@gmail.com</a>> wrote:<br>
>>> >><br>
</div><div class="">>>> >>> - The spaceship operator <=> is equivalent to (a < b) ? -1 : (a> b)<br>
</div>[…]<br>
<div class="">>> if (a.x != b.x) return a.x < b.x ? -1 : 1;<br>
>> if (a.y != b.y) return a.y < b.y ? -1 : 1;<br>
>> // ...<br>
>> return 0;<br>
</div>[…]<br>
<div class="">> If you're suggesting that tie+op< isn't an idiom we should generally adopt<br>
> it'd be nice to build something like it that would be appropriate. (Not sure<br>
> if there's something that should be standardized in some form as this idiom<br>
> seems like it will be common)<br>
<br>
</div>Richard's point is valid.<br>
For the record, the efficient-but-embarrassingly-ugly "std::spaceship"<br>
I was proposing would end up looking something like this.<br></blockquote><div><br></div><div>This is still worst-case 2N comparisons, whereas the ==/< form is worst-case N+1.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

[UNTESTED CODE]<br>
<br>
namespace llvm {<br>
<br>
template <typename... Args, std::size_t... Index><br>
auto subtuple_(const std::tuple<Args...>& a,<br>
std::index_sequence<Index...>) -><br>
decltype(std::tie(std::get<Index+1>(a)...)) {<br>
  return std::tie(std::get<Index+1>(a)...);<br>
}<br>
<br>
template<typename First, typename... Args><br>
auto tuple_tail(const std::tuple<First, Args...>& a) -> std::tuple<Args...><br>
{<br>
    return llvm::subtuple_(a, std::make_integer_sequence<sizeof... Args - 1>());<br>
<div class="">}<br>
<br>
template<typename T> int spaceship(const T& a, const T& b)<br>
{<br>
    return (a < b) ? -1 : (a > b);<br>
}<br>
<br>
</div>int spaceship(const std::tuple<>& a, const std::tuple<>& b)<br>
{<br>
    return 0;<br>
}<br>
<br>
template<typename... Args><br>
int spaceship(const std::tuple<Args…>& a, const std::tuple<Args…>& b)<br>
{<br>
    int result = spaceship(std::get<0>(a), std::get<0>(b));  // uses<br>
argument-dependent lookup<br>
    if (result != 0) return result;<br>
    return spaceship(tuple_tail(a), tuple_tail(b));<br></blockquote><div><br></div><div>This tuple copying makes your approach O(N^2). More efficient implementation (also untested):</div><div><br></div><div>namespace llvm {</div>
<div>template<typename T> int cmp(const T &a, const T &b) {</div><div>  return a < b ? -1 :</div><div>         a > b ? 1 : 0;</div><div>// or for an efficient implementation that assumes == and < are compatible:</div>
<div>//  return a == b ? 0 :</div><div>//         a < b ? -1 : 1;</div><div>}</div><div>template<typename ...Args> int cmp(const std::tuple<Args...> &a, const std::tuple<Args...> &b);</div><div>
<br></div><div>template<typename Tuple, int I, bool Done = I == std::tuple_size<Tuple>::value></div><div>struct cmp_impl {</div><div>  int operator()(const Tuple &a, const Tuple &b) const {<br></div><div>
    int result = cmp(std::get<I>(a), std::get<I>(b));</div><div>    return result ? result : cmp_impl<Tuple, I + 1>()(a, b);</div><div>  }</div><div>};</div><div>template<typename Tuple, int I> struct cmp_impl<Tuple, I, true> {</div>
<div>  int operator()(const Tuple &, const Tuple &) const { return 0; }</div><div>};</div><div>template<typename ...Args></div><div>int cmp(const std::tuple<Args...> &a, const std::tuple<Args...> &b) {<br>
</div><div>  return cmp_impl<std::tuple<Args...>, 0>()(a, b);</div><div>}</div><div>}</div></div></div></div>