Revisiting name lookup with the swap() example

Niels Dekker contributed an interesting bug report regarding the use of swap(). swap() is particularly interesting, because it is essentially the only algorithm in the C++ Standard Library that is really meant to be customized. The example is quite small:

  template <std::Swappable T>
  void SwapTheSwappable(T& lhs, T& rhs) {
    using std::swap;
    swap(lhs, rhs);  // ConceptGCC error: no matching function for call...
  }

This function (SwapTheSwappable) ConceptGCC rejects the call to swap() because the type ‘T’ does not meet the Assignable and CopyConstructible requirements. To see why, we first need to look at std::swap:

  template <typename T>
  where CopyConstructible<T> && Assignable<T>
  void swap(T& x, T& y) {
    T tmp(x);
    x = y;
    y = tmp;
  }

The Swappable concept then looks like this:

  auto concept Swappable<typename > {
    void swap(T&, T&)
  }

For any CopyConstructible and Assignable type, the Swappable requirements are automatically met by the std::swap template. Users can provide their own swap function in an associated namespace or write a concept map to provide a different implementation of swap.

So why does SwapTheSwappable fail? Name lookup for the call swap(lhs, rhs) finds the std::swap declared by the using declaration (“using std::swap”), and stops there. Since this function template requires Assignable and CopyConstructible, which aren’t requirements for SwapThisSwappable, the call fails. ConceptGCC never even looks at the swap() function in the Swappable concept, which would work.

If one removes the “using std::swap” line, ConceptGCC finds swap() in Swappable, and everything works. The problem is that “using std::swap” is the way that C++ programmers have been taught to write templates that use swap(), and it’s unfortunate that the only right way to handle swap in pre-concept code does not work with concepts.

This is a good reason to revisit the “lexical scoping” rule for name lookup into concepts. For instance, if having the using declaration meant only that std::swap would be overloaded with Swappable<T>::swap, the code would still work as intended.

One Response to “Revisiting name lookup with the swap() example”

  1. Niels Dekker Says:

    Thanks Douglas, I very much appreciate the way you deal with my questions regarding std::Swappable.

    Once the problem with “using std::swap” is fixed, it looks like the introduction of the std::Swappable concept would indeed resolve the issue that I submitted to the Library Working Group, http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#594

    Keep up the good work!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.