24

Consider this question, which is about the following code not compiling:

std::vector<int> a, b;
std::cout << (std::ref(a) < std::ref(b));

It doesn't compile because the vector comparison operators for vector are non-member function templates, and implicit conversions aren't allowed to be considered. However, if the operators were instead written as non-member non-template, friend functions:

template <class T, class Allocator = std::allocator<T>>
class vector {
    // ...

    friend bool operator<(const vector& lhs, const vector& rhs) {
        // impl details
    }
};

Then this version of operator< would have been found by ADL and been chosen as the best viable overload, and the original example would have compiled. Given that, is there a reason to prefer the non-member function template that we currently have, or should this be considered a defect in the standard?

Barry
  • 286,269
  • 29
  • 621
  • 977
  • There are similar problems with `operator<<` and streams in a few spots: which does bring something up. I can write a `template operator<<(std::basic_ostream&,std::basic_string&)` *without* depending on more than a forward declaration of (either of the) two. A "Koenig operator" would require at least one of them (which?), does it require both? (this is tangental, as it is about two-type operators, not one like the above) – Yakk - Adam Nevraumont May 15 '15 at 17:28
  • 3
    I don't see why you'd ever write `std::ref(a) < std::ref(b)`. It seems counterintuitive to me that this should work, since `ref` returns an entirely independent class type. – Columbo May 15 '15 at 17:55
  • @Columbo It works for `int`s. Besides, I don't know why you'd ever do lots of stuff - doesn't mean the language doesn't allow it. Also, this would let your class with `operator std::string()` do comparisons against things that `string`s compare against. – Barry May 15 '15 at 21:51
  • 4
    As I've commented on [this related question](http://stackoverflow.com/q/30265627/), the operators typically don't need privileged access. Adding support for `ref(a) < ref(b)` can be done similarly to support for `operator()` by adding a wrapper operator to `reference_wrapper`. It is furthermore unclear to me whether or not it's a good idea to rely on implicit conversions for the application of operators. – dyp May 15 '15 at 22:28

1 Answers1

1

Given that, is there a reason to prefer the non-member function template that we currently have, or should this be considered a defect in the standard?

The reason is if ADL could find out proper function or not. When such a search requires to extract the substituted template parameters from the type of given object and then substitute them many times into a templated parameter of the function template, ADL can't do this because of there are no reasons in the general case to prefer one way of template parameters binding to other. The non-member function template defined after but still in the namespace scope of that template (due to friend) excludes such an indeterminacy.

daramarak
  • 6,115
  • 1
  • 31
  • 50
Aleksey F.
  • 751
  • 7
  • 19