0

Let's consider the following minimal code sample:

// Dummy struct
struct S
{
    int a;
    char * b;

    // Ctors, etc...
};

void swap(S & lhs, S & rhs)
{
    using std::swap;

    swap(lhs.a, rhs.a);
    swap(lhs.b, rhs.b);
}

Context

I know that when we intend to call a swap() function, the proper and recommended way to proceed is to do as follows:

// Let's assume we want to swap two S instances.
using std::swap;
swap(s1, s2);

This way, ADL is able to find the proper overload if any (defined in the given type namespace), otherwise std::swap is used.

Then I read some SO threads:

where the same idiom is used (even for built-in or pointer types), but not only when we call the std::swap() overload but also when we define it.

Question

If the members are all built-in types (or pointer types, possibly pointers to custom types), is it still necessary/recommended to use that idiom instead of explicitly calling std::swap() ?

For example, considering the small code sample I provided, since S members are built-in types, is it fine (well-formed) to define it as below instead:

void swap(S & lhs, S & rhs)
{
    std::swap(lhs.a, rhs.a);
    std::swap(lhs.b, rhs.b);
}

Or maybe is there a reason I couldn't see that would still require to use the using std::swap; way ?

Fareanor
  • 5,900
  • 2
  • 11
  • 37
  • 2
    In those cases, one reason to use `using std::swap;` is future proofing in case `a` or `b` change and become custom (non-built-in, non-std) types. – François Andrieux Oct 19 '21 at 19:16
  • @FrançoisAndrieux I see, it sounds like a good reason. Thanks. – Fareanor Oct 19 '21 at 19:23
  • "If the members are all built-in types", then you probably don't need to implement swap yourself – apple apple Oct 19 '21 at 19:32
  • @appleapple It may still be needed for performances purposes since a custom swap allows to avoid the creation/destruction of a whole instance of the given type (since there is move semantics, this is the only reason I can see to overload `std::swap` no matter built-in types members or not). – Fareanor Oct 19 '21 at 19:36
  • They are all built ins today. Tomorrow (or in six months) they may not be. That's putting the strain of adding a missing using declaration on an unsuspecting future maintainer. So it's ultimately not about language lawyering at all. In C++20 we can just use `std::swap` on every member and the ADL happens automagically, but C++20 isn't quite well supported enough for that to be a strong point – StoryTeller - Unslander Monica Oct 19 '21 at 19:37
  • @StoryTeller-UnslanderMonica In C++20, ADL still happens even if we explicitly call `std::swap` ? It's strange in my opinion since it changes the observable behaviour of the program (if I were to explicitly prefix `std::`, I expect `std::swap` exactly to be called). – Fareanor Oct 19 '21 at 19:41
  • 3
    @Fareanor - Well, it *could* happen. I forgot that in the end `std::swap` was left untouched and `std::ranges::swap` was introduced as a neibloid with the associated magic. – StoryTeller - Unslander Monica Oct 19 '21 at 19:42
  • @StoryTeller-UnslanderMonica Oh I see, that sounds more reasonable. – Fareanor Oct 19 '21 at 19:43

1 Answers1

0

since S members are built-in types, is it fine (well-formed) to define it as below instead: [std::swap usage]

Yes. I mean, it works because std::swap just "swaps the values a and b" if they are both MoveAssignable and MoveConstructible, which built-in types are.

If the members are all built-in types (or pointer types, possibly pointers to custom types), is it still necessary/recommended to use that idiom instead of explicitly calling std::swap() ?

Just for the future of your class: if one day any of its members gets replaced with a user-defined type, you might forget to modify your swap and miss a "specialized" ADL implementation for it, still calling the generic std::swap which could (theoretically) be inefficient yet still compile.

Actually, you don't even need to think about it if you just always use boost::swap or implement it yourself:

template<typename T> void swap(T& a, T& b) {
    using std::swap;
    swap(a, b);
}
passing_through
  • 1,778
  • 12
  • 24
  • Implementing my own swap as proposed wouldn't be helpful since it would probably never be called (except if I call it explicitly). It's better to save ourselves a function call and to directly use `using std::swap; swap(lhs, rhs);` – Fareanor Oct 22 '21 at 07:54