Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are std::vector and std::string's comparison operators defined as template functions?

A little overview. I'm writing a class template that provides a strong typedef; by strong typedef I am contrasting with a regular typedef which just declares an alias. To give an idea:

using EmployeeId = StrongTypedef<int>;

Now, there are different schools of thought on strong typedefs and implicit conversions. One of these schools says: not every integer is an EmployeeId, but every EmployeeId is an integer, so you should allow implicit conversions from EmployeeId to integer. And you can implement this, and write things like:

EmployeeId x(4);
assert(x == 4);

This works because x gets implicitly converted to an integer, and then integer equality comparison is used. So far, so good. Now, I want to do this with a vector of integers:

using EmployeeScores = StrongTypedef<std::vector<int>>;

So I can do things like this:

std::vector<int> v1{1,2};
EmployeeScores e(v1);
std::vector<int> v2(e); // implicit conversion
assert(v1 == v2);

But I still can't do this:

assert(v1 == e);

The reason this doesn't work is because of how std::vector defines its equality check, basically (modulo standardese):

template <class T, class A>
bool operator==(const vector<T,A> & v1, const vector<T,A> & v2) {
...
}

This is a function template; because it gets discarded in an earlier phase of lookup it will not allow a type that converts implicitly to vector to be compared.

A different way to define equality would be like this:

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

  friend bool operator==(const vector & v1, const vector & v2) {
  ...
}

} // end of class vector

In this second case, the equality operator is not a function template, it's just a regular function that's generated along with the class, similar to a member function. This is an unusual case enabled by the friend keyword.

The question (sorry the background was so long), is why doesn't std::vector use the second form instead of the first? This makes vector behave more like primitive types, and as you can clearly see it helps with my use case. This behavior is even more surprising with string since it's easy to forget that string is just a typedef of a class template.

Two things I've considered: first, some may think that because the friend function gets generated with the class, this will cause a hard failure if the contained type of the vector does not support equality comparison. This is not the case; like member functions of template classes, they aren't generated if unused. Second, in the more general case, free functions have the advantage that they don't need to be defined in the same header as the class, which can have advantages. But this clearly isn't utilized here.

So, what gives? Is there a good reason for this, or was it just a sub-optimal choice?

Edit: I wrote a quick example that demonstrates two things: both that implicit conversion works as desired with the friend approach, and that no hard failures are caused if the templated type doesn't meet the requirements of the equality operator (obviously, assuming the equality operator is not used in that case). Edit: improved to contrast with the first approach: http://coliru.stacked-crooked.com/a/6f8910945f4ed346.

like image 548
Nir Friedman Avatar asked Dec 30 '15 23:12

Nir Friedman


People also ask

What is an std :: vector?

1) std::vector is a sequence container that encapsulates dynamic size arrays. 2) std::pmr::vector is an alias template that uses a polymorphic allocator. The elements are stored contiguously, which means that elements can be accessed not only through iterators, but also using offsets to regular pointers to elements.

Which operator can be used to compare two values in C++?

The equality operator (==) is used to compare two values or expressions.

Which is the comparison operator?

Comparison operators can compare numbers or strings and perform evaluations. Expressions that use comparison operators do not return a number value as do arithmetic expressions. Comparison expressions return either 1 , which represents true, or 0 , which represents false.


1 Answers

The techique you describe (what I call Koenig operators) was not known, at least not widely, at the point vector was designed and originally specified.

Changing it now would require more care than using it originally, and more justification.

As a guess, today Koenig operators would be used in place of template operators.

like image 148
Yakk - Adam Nevraumont Avatar answered Nov 16 '22 13:11

Yakk - Adam Nevraumont