Topic: namespace no_adl
Author: "Mark A. Gibbs" <indi.in.the.wired@gmail.com>
Date: Mon, 12 Jan 2015 21:22:42 -0800 (PST)
Raw View
------=_Part_949_1088720167.1421126562421
Content-Type: multipart/alternative;
boundary="----=_Part_950_1559174329.1421126562421"
------=_Part_950_1559174329.1421126562421
Content-Type: text/plain; charset=UTF-8
Has anyone ever proposed using a sub-namespace to solve the ADL problem?
Right now, things like std::swap() are kinda clunky to use properly,
because the generic implementation is in std. That means when you say "std::swap(x,
y);", you are saying "I want the generic implementation of swap", which
rules out using specialized implementations (that aren't in std). The
solution right now is to say "using std::swap; swap(x, y);", which allows
ADL to select a specialized implementation if available, (ie, if one exists
in the same namespace as the declaration of the type of x and y) and fall
back on the generic implementation.
But writing "using std::func; func(???);" to use every "std::func()" that
leverages ADL is verbose and error-prone, and explaining to beginners why
it's necessary - especially at early stages - is a pain. As more and more
non-member functions intended to be used with ADL get added - std::size(),
std::empty(), and also see numerous proposals like N4183 - it's just going
to get worse. Every non-trivial generic function body is going to start to
look like this:
auto foo(...)
{
using std::swap;
using std::begin;
using std::end;
using std::size;
using std::empty;
using std::data;
// ...
// actual function body
}
(Either that or the dreaded "using namespace std;".)
I have been musing over possibilities to avoid all this mess and have
std::func() use ADL to select a specialized implementation then fall back
on a generic implementation.
I saw Eric Neibler's post about "customization points"
<http://ericniebler.com/2014/10/21/customization-point-design-in-c11-and-beyond/>,
where he offered a clever solution using a global function object, but that
struck me as over-engineering what should be a simple problem. It also
doesn't easily allow *forcing* the use of the generic implementation, if
that's what you really want.
It seems to me all we really need is a special namespace for generic
implementations, so the function in namespace std uses ADL to search for a
specialized implementation then falls back on the generic implementation.
For example (I'm going to be using swap since that's the function most
people associate with the ADL problem, but I'm going to simplify it for
readability, ignoring exception specifications and so on):
namespace std {
namespace no_adl {
// Generic (fallback) implementation
template <typename T>
void swap(T& a, T& b)
{
auto t = move(a);
a = move(b);
b = move(t);
}
} // namespace no_adl
// Dispatch function
template <typename T>
void swap(T& a, T& b)
{
using no_adl::swap;
swap(a, b);
}
// other swap specializations in namespace std
// for example...
void swap(thread& a, thread& b)
{
a.swap(b);
}
template <typename T, typename Alloc>
void swap(vector<T, Alloc>& a, vector<T, Alloc>& b)
{
a.swap(b);
}
} // namespace std
The effects of this change would be this:
// Currently recommended method
using std::swap;
swap(a, b);
// C++14: uses ADL with fallback on generic impl
// Proposed: uses ADL with fallback on generic impl
// Natural method
std::swap(a, b);
// C++14: forces generic impl (usually by accident)
// Proposed: uses ADL with fallback on generic impl
// Force generic impl
std::no_adl::swap(a, b);
// C++14: n/a
// Proposed: forces generic impl (explicitly)
As you can see, the natural and simple way of using swap - by saying "std::swap(a,
b);" - Just Works; you automatically get an ADL-powered search for the most
optimized swap implementation, falling back on the generic implementation.
The same pattern would work for any function that could benefit from
ADL-found specializations. There would be no need for the kind of dance
N4183 proposes - with std::pointer_from and std::do_pointer_from, etc.; you
only need one name. Existing code that specializes swap (in the literal
sense, by actually creating a specialization in namespace std) would also
still work.
The only "gotcha" is that the behaviour of code that now uses the qualified
call "std::swap(a, b);" would change. However, I would argue that this
isn't really a problem, because virtually all uses of a qualified call in
generic code are almost certainly mistakes. At best, it's harmless (for
built-in types and std types), but at worst it's picking a non-optimized
swap implementation. In the astronomically-rare case where you *really*,
*specifically* want the generic implementation even when a specialized
implementation exists, you do have that option (by saying "std::no_adl::swap(a,
b);", which is also self-documenting).
Has this idea been floated before? What was the consensus?
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_950_1559174329.1421126562421
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Has anyone ever proposed using a sub-namespace to solve th=
e ADL problem?<br><br>Right now, things like <span style=3D"font-family: co=
urier new,monospace;">std::swap()</span> are kinda clunky to use properly, =
because the generic implementation is in <span style=3D"font-family: courie=
r new,monospace;">std</span>. That means when you say "<span style=3D"font-=
family: courier new,monospace;">std::swap(x, y);</span>", you are saying "I=
want the generic implementation of swap", which rules out using specialize=
d implementations (that aren't in <span style=3D"font-family: courier new,m=
onospace;">std</span>). The solution right now is to say "<span style=3D"fo=
nt-family: courier new,monospace;">using std::swap; swap(x, y);</span>", wh=
ich allows ADL to select a specialized implementation if available, (ie, if=
one exists in the same namespace as the declaration of the type of <span s=
tyle=3D"font-family: courier new,monospace;">x</span> and <span style=3D"fo=
nt-family: courier new,monospace;">y</span>) and fall back on the generic i=
mplementation.<span style=3D"color: #080;" class=3D"styled-by-prettify"><br=
></span><code class=3D"prettyprint"></code><br>But writing "<span style=3D"=
font-family: courier new,monospace;">using std::func; func(???);</span>" to=
use every "<span style=3D"font-family: courier new,monospace;">std::func()=
</span>" that leverages ADL is verbose and error-prone, and explaining to b=
eginners why it's necessary - especially at early stages - is a pain. As mo=
re and more non-member functions intended to be used with ADL get added - <=
span style=3D"font-family: courier new,monospace;">std::size()</span>, <spa=
n style=3D"font-family: courier new,monospace;">std::empty()</span>, and al=
so see numerous proposals like N4183 - it's just going to get worse. Every =
non-trivial generic function body is going to start to look like this:<br><=
br><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250)=
; border-color: rgb(187, 187, 187); border-style: solid; border-width: 1px;=
word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprett=
yprint"><span style=3D"color: #008;" class=3D"styled-by-prettify">auto</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> foo</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">(...)</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"><br> </span><span style=3D"color: #=
008;" class=3D"styled-by-prettify">using</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify"> std</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify">swap</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
><br> </span><span style=3D"color: #008;" class=3D"styled-by-prettify=
">using</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> st=
d</span><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span>=
<span style=3D"color: #008;" class=3D"styled-by-prettify">begin</span><span=
style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"><br> </span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">using</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> std</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">::</span><span style=3D"color: #008;" c=
lass=3D"styled-by-prettify">end</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"><br> </span><span style=3D"color: #008;" class=3D"styled-=
by-prettify">using</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> std</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">size</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"><br> </span><sp=
an style=3D"color: #008;" class=3D"styled-by-prettify">using</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> std</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify">empty</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br> </span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">using</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> std</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify">data</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br> =
; </span><span style=3D"color: #800;" class=3D"styled-by-prettify">// ...</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br> <=
br> </span><span style=3D"color: #800;" class=3D"styled-by-prettify">=
// actual function body</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"><br></span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">}</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><b=
r></span></div></code></div><br>(Either that or the dreaded "<span style=3D=
"font-family: courier new,monospace;">using namespace std;</span>".)<br><br=
>I have been musing over possibilities to avoid all this mess and have <spa=
n style=3D"font-family: courier new,monospace;">std::func()</span> use ADL =
to select a specialized implementation then fall back on a generic implemen=
tation.<br><br>I saw <a href=3D"http://ericniebler.com/2014/10/21/customiza=
tion-point-design-in-c11-and-beyond/">Eric Neibler's post about "customizat=
ion points"</a>, where he offered a clever solution using a global function=
object, but that struck me as over-engineering what should be a simple pro=
blem. It also doesn't easily allow <i>forcing</i> the use of the generic im=
plementation, if that's what you really want.<br><br>It seems to me all we =
really need is a special namespace for generic implementations, so the func=
tion in namespace <span style=3D"font-family: courier new,monospace;">std</=
span> uses ADL to search for a specialized implementation then falls back o=
n the generic implementation.<br><br>For example (I'm going to be using swa=
p since that's the function most people associate with the ADL problem, but=
I'm going to simplify it for readability, ignoring exception specification=
s and so on):<br><br><div class=3D"prettyprint" style=3D"background-color: =
rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-style: solid; =
border-width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div=
class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">namespace</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> std </span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><b=
r></span><span style=3D"color: #008;" class=3D"styled-by-prettify">namespac=
e</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> no_adl <=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br><br></span><span=
style=3D"color: #800;" class=3D"styled-by-prettify">// Generic (fallback) =
implementation</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"><br></span><span style=3D"color: #008;" class=3D"styled-by-prettify">te=
mplate</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify"><</span><s=
pan style=3D"color: #008;" class=3D"styled-by-prettify">typename</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> T</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">></span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #=
008;" class=3D"styled-by-prettify">void</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> swap</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify">T</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">&</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> a</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> T</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">&</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> b</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">)</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br> </span><span style=3D"color: #008;" class=3D"styl=
ed-by-prettify">auto</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> t </span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> mov=
e</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify">a</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br> a </span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> move</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">b</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">);</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"><br> b </span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> move</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify">t</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">}</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"><br><br></span><span style=3D"color: #660;"=
class=3D"styled-by-prettify">}</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> </span><span style=3D"color: #800;" class=3D"styled-b=
y-prettify">// namespace no_adl</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"><br><br></span><span style=3D"color: #800;" class=3D"s=
tyled-by-prettify">// Dispatch function</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><br></span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">template</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"style=
d-by-prettify"><</span><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">typename</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> T</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&=
gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></s=
pan><span style=3D"color: #008;" class=3D"styled-by-prettify">void</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> swap</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify">T</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">&</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"> a</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> T</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">&</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> b=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"><br> </span><span style=3D"c=
olor: #008;" class=3D"styled-by-prettify">using</span><span style=3D"color:=
#000;" class=3D"styled-by-prettify"> no_adl</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">::</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify">swap</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"><br> swap</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify">a</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> b</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">}</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"><br><br></span><span style=3D"color: #800;=
" class=3D"styled-by-prettify">// other swap specializations in namespace s=
td</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></sp=
an><span style=3D"color: #800;" class=3D"styled-by-prettify">// for example=
....</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></s=
pan><span style=3D"color: #008;" class=3D"styled-by-prettify">void</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> swap</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify">thread</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">&</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> a</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> thread</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">&</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> b</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
)</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"><br> a</span><span=
style=3D"color: #660;" class=3D"styled-by-prettify">.</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify">swap</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify">b</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">);</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"><br></span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">}</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br=
><br></span><span style=3D"color: #008;" class=3D"styled-by-prettify">templ=
ate</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span style=3D"color: #660;" class=3D"styled-by-prettify"><</span><span=
style=3D"color: #008;" class=3D"styled-by-prettify">typename</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> T</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">typename</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #606;" class=3D"style=
d-by-prettify">Alloc</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">></span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"><br></span><span style=3D"color: #008;" class=3D"styled-by-prettify">vo=
id</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> swap</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify">vector</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify"><</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify">T</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> </span><span style=3D"color: #606;" class=3D"styl=
ed-by-prettify">Alloc</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">>&</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> a</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> vector=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify"><</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify">T</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #606=
;" class=3D"styled-by-prettify">Alloc</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">>&</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> b</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">)</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"><br></span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&n=
bsp; a</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify">swap</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">b</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">}</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br><br></span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">}</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> </span><span style=3D"color: #800;" class=3D"styled-by-prettify">// na=
mespace std</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
><br></span></div></code></div><br>The effects of this change would be this=
:<br><br><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250=
, 250); border-color: rgb(187, 187, 187); border-style: solid; border-width=
: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"su=
bprettyprint"><span style=3D"color: #800;" class=3D"styled-by-prettify">// =
Currently recommended method</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"><br></span><span style=3D"color: #008;" class=3D"styled-b=
y-prettify">using</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> std</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">swap</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify"><br>swap</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify">a</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> b</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">);</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"><br></span><span style=3D"color: #800;" class=3D"styled-by-prettify=
">// C++14: uses ADL with fallback on generic impl</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=
=3D"color: #800;" class=3D"styled-by-prettify">// Proposed: uses ADL with f=
allback on generic impl</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"><br><br></span><span style=3D"color: #800;" class=3D"styled-by=
-prettify">// Natural method</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"><br>std</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify">swap</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">a</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> b</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #800;" cl=
ass=3D"styled-by-prettify">// C++14: forces generic impl (usua=
lly by accident)</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"><br></span><span style=3D"color: #800;" class=3D"styled-by-prettify">=
// Proposed: uses ADL with fallback on generic impl</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"><br><br></span><span style=3D"colo=
r: #800;" class=3D"styled-by-prettify">// Force generic impl</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br>std</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify">no_adl</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">::</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify">swap</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify">a</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> b</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=
=3D"color: #800;" class=3D"styled-by-prettify">// C++14: n/a</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><=
span style=3D"color: #800;" class=3D"styled-by-prettify">// Proposed: force=
s generic impl (explicitly)</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"><br></span></div></code></div><br>As you can see, the natu=
ral and simple way of using swap - by saying "<span style=3D"font-family: c=
ourier new,monospace;">std::swap(a, b);</span>" - Just Works; you automatic=
ally get an ADL-powered search for the most optimized swap implementation, =
falling back on the generic implementation.<br><br>The same pattern would w=
ork for any function that could benefit from ADL-found specializations. The=
re would be no need for the kind of dance N4183 proposes - with <span style=
=3D"font-family: courier new,monospace;">std::pointer_from</span> and <span=
style=3D"font-family: courier new,monospace;">std::do_pointer_from</span>,=
etc.; you only need one name. Existing code that specializes swap (in the =
literal sense, by actually creating a specialization in namespace <span sty=
le=3D"font-family: courier new,monospace;">std</span>) would also still wor=
k.<br><br>The only "gotcha" is that the behaviour of code that now uses the=
qualified call "<span style=3D"font-family: courier new,monospace;">std::s=
wap(a, b);</span>" would change. However, I would argue that this isn't rea=
lly a problem, because virtually all uses of a qualified call in generic co=
de are almost certainly mistakes. At best, it's harmless (for built-in type=
s and std types), but at worst it's picking a non-optimized swap implementa=
tion. In the astronomically-rare case where you <i>really</i>, <i>specifica=
lly</i> want the generic implementation even when a specialized implementat=
ion exists, you do have that option (by saying "<span style=3D"font-family:=
courier new,monospace;">std::no_adl::swap(a, b);</span>", which is also se=
lf-documenting).<br><br>Has this idea been floated before? What was the con=
sensus?<br></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_950_1559174329.1421126562421--
------=_Part_949_1088720167.1421126562421--
.
Author: David Krauss <potswa@gmail.com>
Date: Tue, 13 Jan 2015 13:42:23 +0800
Raw View
--Apple-Mail=_3E2D9212-A82B-4F67-9584-9655D8FED77A
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=UTF-8
> On 2015=E2=80=9301=E2=80=9313, at 1:22 PM, Mark A. Gibbs <indi.in.the.wir=
ed@gmail.com> wrote:
>=20
> // Natural method
> std::swap(a, b);
> // C++14: forces generic impl (usually by accident)
> // Proposed: uses ADL with fallback on generic impl
Even if it=E2=80=99s usually done by accident, changing the behavior of suc=
h code makes the proposal a breaking change.
How about a namespace adl instead?
std::adl::swap( a, b );
One particularly easy solution is to create a namespace containing function=
s that should only be used with ADL.
namespace import_adl {
using std::swap;
}
using namespace import_adl; is then far less toxic than using namespace std=
;, although the bigger solution is probably better in the long run.
> auto foo(...)
> {
> using std::swap;
> using std::begin;
> using std::end;
> using std::size;
> using std::empty;
> using std::data;
> // ...
> =20
> // actual function body
> }
We don=E2=80=99t have size, empty, or data, and along with begin and end, t=
he argument for ADL is weak. These functions support C arrays, which are th=
e only non-class types for which they are reasonable. The only other argume=
nt I=E2=80=99ve heard is that enumerations should be treated as iterators w=
ith enumerators as both the iterator values and the iterated-range values. =
That=E2=80=99s just bogus; you can define a suitable =E2=80=9Cnumeric itera=
tor=E2=80=9D yourself without changing fundamental practices.
So that leaves std::swap as the only standard ADL function, which takes awa=
y some degree of motivation. I=E2=80=99d add the <cmath> functions as good =
candidates, but for that we already have <math.h> which puts them in the gl=
obal namespace, and then unqualified calls work naturally.
--=20
---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.
--Apple-Mail=_3E2D9212-A82B-4F67-9584-9655D8FED77A
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=UTF-8
<html><head><meta http-equiv=3D"Content-Type" content=3D"text/html charset=
=3Dutf-8"></head><body style=3D"word-wrap: break-word; -webkit-nbsp-mode: s=
pace; -webkit-line-break: after-white-space;" class=3D""><br class=3D""><di=
v><blockquote type=3D"cite" class=3D""><div class=3D"">On 2015=E2=80=9301=
=E2=80=9313, at 1:22 PM, Mark A. Gibbs <<a href=3D"mailto:indi.in.the.wi=
red@gmail.com" class=3D"">indi.in.the.wired@gmail.com</a>> wrote:</div><=
br class=3D"Apple-interchange-newline"><div class=3D""><div class=3D"pretty=
print" style=3D"font-family: Helvetica; font-size: 12px; font-style: normal=
; font-variant: normal; font-weight: normal; letter-spacing: normal; line-h=
eight: normal; orphans: auto; text-align: start; text-indent: 0px; text-tra=
nsform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit=
-text-stroke-width: 0px; background-color: rgb(250, 250, 250); border: 1px =
solid rgb(187, 187, 187); word-wrap: break-word;"><code class=3D"prettyprin=
t"><span class=3D"styled-by-prettify" style=3D"color: rgb(136, 0, 0);">// N=
atural method</span><br class=3D"">std<span class=3D"styled-by-prettify" st=
yle=3D"color: rgb(102, 102, 0);">::</span>swap<span class=3D"styled-by-pret=
tify" style=3D"color: rgb(102, 102, 0);">(</span>a<span class=3D"styled-by-=
prettify" style=3D"color: rgb(102, 102, 0);">,</span><span class=3D"Apple-c=
onverted-space"> </span>b<span class=3D"styled-by-prettify" style=3D"c=
olor: rgb(102, 102, 0);">);</span><br class=3D""><span class=3D"styled-by-p=
rettify" style=3D"color: rgb(136, 0, 0);">// C++14: forces gen=
eric impl (usually by accident)</span><br class=3D""><span class=3D"styled-=
by-prettify" style=3D"color: rgb(136, 0, 0);">// Proposed: uses ADL with fa=
llback on generic impl</span><br class=3D""></code></div></div></blockquote=
><div><br class=3D""></div><div>Even if it=E2=80=99s usually done by accide=
nt, changing the behavior of such code makes the proposal a breaking change=
..</div><div><br class=3D""></div><div>How about a namespace <font face=3D"C=
ourier" class=3D"">adl</font> instead?</div><div><br class=3D""></div><div>=
<font face=3D"Courier" class=3D"">std::adl::swap( a, b );</font></div><div>=
<br class=3D""></div><div>One particularly easy solution is to create a nam=
espace containing functions that should only be used with ADL.</div><div><b=
r class=3D""></div><div><font face=3D"Courier" class=3D"">namespace import_=
adl {</font></div><div><font face=3D"Courier" class=3D""> usin=
g std::swap;</font></div><div><font face=3D"Courier" class=3D"">}</font></d=
iv><div><br class=3D""></div><div><font face=3D"Courier" class=3D"">using n=
amespace import_adl;</font> is then far less toxic than <font face=3D"Couri=
er" class=3D"">using namespace std;</font>, although the bigger solution is=
probably better in the long run.</div><div><br class=3D""></div><div><bloc=
kquote type=3D"cite" class=3D""><span class=3D"styled-by-prettify" style=3D=
"font-family: monospace; color: rgb(0, 0, 136);">auto</span><span class=3D"=
styled-by-prettify" style=3D"font-family: monospace;"> foo</span><span=
class=3D"styled-by-prettify" style=3D"font-family: monospace; color: rgb(1=
02, 102, 0);">(...)</span><span class=3D"styled-by-prettify" style=3D"font-=
family: monospace;"><br class=3D""></span><span class=3D"styled-by-prettify=
" style=3D"font-family: monospace; color: rgb(102, 102, 0);">{</span><span =
class=3D"styled-by-prettify" style=3D"font-family: monospace;"><br class=3D=
""> </span><span class=3D"styled-by-prettify" style=3D"font-fami=
ly: monospace; color: rgb(0, 0, 136);">using</span><span class=3D"styled-by=
-prettify" style=3D"font-family: monospace;"> std</span><span class=3D=
"styled-by-prettify" style=3D"font-family: monospace; color: rgb(102, 102, =
0);">::</span><span class=3D"styled-by-prettify" style=3D"font-family: mono=
space;">swap</span><span class=3D"styled-by-prettify" style=3D"font-family:=
monospace; color: rgb(102, 102, 0);">;</span><span class=3D"styled-by-pret=
tify" style=3D"font-family: monospace;"><br class=3D""> </span><=
span class=3D"styled-by-prettify" style=3D"font-family: monospace; color: r=
gb(0, 0, 136);">using</span><span class=3D"styled-by-prettify" style=3D"fon=
t-family: monospace;"> std</span><span class=3D"styled-by-prettify" st=
yle=3D"font-family: monospace; color: rgb(102, 102, 0);">::</span><span cla=
ss=3D"styled-by-prettify" style=3D"font-family: monospace; color: rgb(0, 0,=
136);">begin</span><span class=3D"styled-by-prettify" style=3D"font-family=
: monospace; color: rgb(102, 102, 0);">;</span><span class=3D"styled-by-pre=
ttify" style=3D"font-family: monospace;"><br class=3D""> </span>=
<span class=3D"styled-by-prettify" style=3D"font-family: monospace; color: =
rgb(0, 0, 136);">using</span><span class=3D"styled-by-prettify" style=3D"fo=
nt-family: monospace;"> std</span><span class=3D"styled-by-prettify" s=
tyle=3D"font-family: monospace; color: rgb(102, 102, 0);">::</span><span cl=
ass=3D"styled-by-prettify" style=3D"font-family: monospace; color: rgb(0, 0=
, 136);">end</span><span class=3D"styled-by-prettify" style=3D"font-family:=
monospace; color: rgb(102, 102, 0);">;</span><span class=3D"styled-by-pret=
tify" style=3D"font-family: monospace;"><br class=3D""> </span><=
span class=3D"styled-by-prettify" style=3D"font-family: monospace; color: r=
gb(0, 0, 136);">using</span><span class=3D"styled-by-prettify" style=3D"fon=
t-family: monospace;"> std</span><span class=3D"styled-by-prettify" st=
yle=3D"font-family: monospace; color: rgb(102, 102, 0);">::</span><span cla=
ss=3D"styled-by-prettify" style=3D"font-family: monospace;">size</span><spa=
n class=3D"styled-by-prettify" style=3D"font-family: monospace; color: rgb(=
102, 102, 0);">;</span><span class=3D"styled-by-prettify" style=3D"font-fam=
ily: monospace;"><br class=3D""> </span><span class=3D"styled-by=
-prettify" style=3D"font-family: monospace; color: rgb(0, 0, 136);">using</=
span><span class=3D"styled-by-prettify" style=3D"font-family: monospace;">&=
nbsp;std</span><span class=3D"styled-by-prettify" style=3D"font-family: mon=
ospace; color: rgb(102, 102, 0);">::</span><span class=3D"styled-by-prettif=
y" style=3D"font-family: monospace;">empty</span><span class=3D"styled-by-p=
rettify" style=3D"font-family: monospace; color: rgb(102, 102, 0);">;</span=
><span class=3D"styled-by-prettify" style=3D"font-family: monospace;"><br c=
lass=3D""> </span><span class=3D"styled-by-prettify" style=3D"fo=
nt-family: monospace; color: rgb(0, 0, 136);">using</span><span class=3D"st=
yled-by-prettify" style=3D"font-family: monospace;"> std</span><span c=
lass=3D"styled-by-prettify" style=3D"font-family: monospace; color: rgb(102=
, 102, 0);">::</span><span class=3D"styled-by-prettify" style=3D"font-famil=
y: monospace;">data</span><span class=3D"styled-by-prettify" style=3D"font-=
family: monospace; color: rgb(102, 102, 0);">;</span><span class=3D"styled-=
by-prettify" style=3D"font-family: monospace;"><br class=3D""> <=
/span><span class=3D"styled-by-prettify" style=3D"font-family: monospace; c=
olor: rgb(136, 0, 0);">// ...</span><span class=3D"styled-by-prettify" styl=
e=3D"font-family: monospace;"><br class=3D""> <br class=3D"">&nb=
sp; </span><span class=3D"styled-by-prettify" style=3D"font-family: mo=
nospace; color: rgb(136, 0, 0);">// actual function body</span><span class=
=3D"styled-by-prettify" style=3D"font-family: monospace;"><br class=3D""></=
span><span class=3D"styled-by-prettify" style=3D"font-family: monospace; co=
lor: rgb(102, 102, 0);">}</span><span class=3D"styled-by-prettify" style=3D=
"font-family: monospace;"><br class=3D""></span></blockquote><div class=3D"=
"><br class=3D""></div><div class=3D"">We don=E2=80=99t have <font face=3D"=
Courier" class=3D"">size</font>, <font face=3D"Courier" class=3D"">empty</f=
ont>, or <font face=3D"Courier" class=3D"">data</font>, and along with <fon=
t face=3D"Courier" class=3D"">begin</font> and <font face=3D"Courier" class=
=3D"">end</font>, the argument for ADL is weak. These functions support C a=
rrays, which are the only non-class types for which they are reasonable. Th=
e only other argument I=E2=80=99ve heard is that enumerations should be tre=
ated as iterators with enumerators as both the iterator values and the iter=
ated-range values. That=E2=80=99s just bogus; you can define a suitable =E2=
=80=9Cnumeric iterator=E2=80=9D yourself without changing fundamental pract=
ices.</div><div class=3D""><br class=3D""></div><div class=3D"">So that lea=
ves <font face=3D"Courier" class=3D"">std::swap</font> as the only standard=
ADL function, which takes away some degree of motivation. I=E2=80=99d add =
the <font face=3D"Courier" class=3D""><cmath></font> functions as goo=
d candidates, but for that we already have <font face=3D"Courier" class=3D"=
"><math.h></font> which puts them in the global namespace, and then u=
nqualified calls work naturally.</div></div></div></body></html>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
--Apple-Mail=_3E2D9212-A82B-4F67-9584-9655D8FED77A--
.
Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Tue, 13 Jan 2015 07:44:58 +0200
Raw View
On 13 January 2015 at 07:22, Mark A. Gibbs <indi.in.the.wired@gmail.com> wrote:
> Has this idea been floated before? What was the consensus?
Probably not in an actual proposal, but the problem space has been
explored, see
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3490.html
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
.
Author: =?UTF-8?Q?David_Rodr=C3=ADguez_Ibeas?= <dibeas@ieee.org>
Date: Tue, 13 Jan 2015 09:41:56 -0500
Raw View
--001a113fb64ee452eb050c899f18
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
There is more to using declaration that meets the eye here. The using
declaration makes the function available for regular lookup at the location
where the declaration happens, which is effectively an ADL-enabler. Using
the example of 'std::swap', when the user does:
struct T {
U member;
void swap(T & other) {
using ::std::swap;
swap(member, other.member);
}
};
The using declaration brings ::std::swap (free function) into the scope of
the declaration, in doing so it provides a default implementation if there
is no overload for 'swap' taking two 'U' object, but more importantly it
*enables* ADL. If you remove that using declaration, regarless of whether
there is an overload of 'swap' that could be found by ADL for the type 'U',
it will fail to compile.
Why? Without the local declaration introduced by 'using ::std::swap',
normal lookup will find member 'T::swap' and it won't attempt ADL at all.
I honestly believe that more emphasis should be placed in teaching this
particular
There are already two comments in three emails on this topic that mention
something in the lines of *the dreaded "using namespace std"*; yes, they
are dreaded, but more than that, they are not even a solution to the
problem as they don't enable ADL. The symbols in the used namespace will be
visible in an enclosing namespace, if normal lookup finds anything with
that name other than a free function before hitting that, ADL will not kick
in.
I have discussed this problem in the past with different people, including
Dietmar Kh=C3=BCl, who might have been the first to suggest that the proble=
m is
that we have built a mechanism with two overlapping interfaces. In the
same way that NVI suggests separating the user interface (public part of a
class) with the extension interface (virtual member functions), we should
have provided two interfaces. The main problem is that this ship has
sailed, long ago.
When reading your proposal I see an attempt to get something similar to
this, that does not require the introduction of a different name, since the
user interface (::std::swap) and the implementation (::std::no_adl::swap)
differ in the namespace where they live.
This is good, with the potential issue that it is a breaking change. If
today I call ::std::swap, I am explicitly selecting the overload that I
want, and requesting move/swaps, not asking for any ADL, and the change
changes the semantics of my program. Whether this is truly an issue or not
is a different thing, and I personally find this acceptable. A different
option would be to leave what we have as it is, but provide a different
name for the user interface:
template <typename T>
void ::std::do_swap(T& a, T& b) {
swap(a,b); // /no 'using ::std::swap needed here, we are inside ::std
}
All existing code would use the old style and have the old behavior. New
user implementations of 'swap' and use fully qualified 'do_swap'
('adl_swap'?):
struct T {
U member;
void swap(T & other) { ::std::do_swap(member, other.member); }
};
void swap(T& a, T& b) { ::std::do_swap(a.member, b.member); }
This goes a bit more in the lines of David Krauss' suggestion of having an
'adl' (rather than a 'no_adl') namespace. It imposes a higher cost on the
user to ensure that the behavior of existing code does not change in the
process.
Whatever the option taken for the existing functions is, I would suggest
that we avoid making the same mistake of merging the user/extension
interfaces the same for newer components. And more than that, we should
make sure that new comers into the language are correctly taught that using
declarations (not directives!) are ADL enablers even if we provide a
simplification of the use case and this is no longer a problem within the
standard library.
David
On Tue, Jan 13, 2015 at 12:22 AM, Mark A. Gibbs <indi.in.the.wired@gmail.co=
m
> wrote:
> Has anyone ever proposed using a sub-namespace to solve the ADL problem?
>
> Right now, things like std::swap() are kinda clunky to use properly,
> because the generic implementation is in std. That means when you say "st=
d::swap(x,
> y);", you are saying "I want the generic implementation of swap", which
> rules out using specialized implementations (that aren't in std). The
> solution right now is to say "using std::swap; swap(x, y);", which allows
> ADL to select a specialized implementation if available, (ie, if one exis=
ts
> in the same namespace as the declaration of the type of x and y) and fall
> back on the generic implementation.
>
> But writing "using std::func; func(???);" to use every "std::func()" that
> leverages ADL is verbose and error-prone, and explaining to beginners why
> it's necessary - especially at early stages - is a pain. As more and more
> non-member functions intended to be used with ADL get added - std::size()=
,
> std::empty(), and also see numerous proposals like N4183 - it's just
> going to get worse. Every non-trivial generic function body is going to
> start to look like this:
>
> auto foo(...)
> {
> using std::swap;
> using std::begin;
> using std::end;
> using std::size;
> using std::empty;
> using std::data;
> // ...
>
> // actual function body
> }
>
> (Either that or the dreaded "using namespace std;".)
>
> I have been musing over possibilities to avoid all this mess and have
> std::func() use ADL to select a specialized implementation then fall back
> on a generic implementation.
>
> I saw Eric Neibler's post about "customization points"
> <http://ericniebler.com/2014/10/21/customization-point-design-in-c11-and-=
beyond/>,
> where he offered a clever solution using a global function object, but th=
at
> struck me as over-engineering what should be a simple problem. It also
> doesn't easily allow *forcing* the use of the generic implementation, if
> that's what you really want.
>
> It seems to me all we really need is a special namespace for generic
> implementations, so the function in namespace std uses ADL to search for
> a specialized implementation then falls back on the generic implementatio=
n.
>
> For example (I'm going to be using swap since that's the function most
> people associate with the ADL problem, but I'm going to simplify it for
> readability, ignoring exception specifications and so on):
>
> namespace std {
>
> namespace no_adl {
>
> // Generic (fallback) implementation
> template <typename T>
> void swap(T& a, T& b)
> {
> auto t =3D move(a);
> a =3D move(b);
> b =3D move(t);
> }
>
> } // namespace no_adl
>
> // Dispatch function
> template <typename T>
> void swap(T& a, T& b)
> {
> using no_adl::swap;
> swap(a, b);
> }
>
> // other swap specializations in namespace std
> // for example...
> void swap(thread& a, thread& b)
> {
> a.swap(b);
> }
>
> template <typename T, typename Alloc>
> void swap(vector<T, Alloc>& a, vector<T, Alloc>& b)
> {
> a.swap(b);
> }
>
> } // namespace std
>
> The effects of this change would be this:
>
> // Currently recommended method
> using std::swap;
> swap(a, b);
> // C++14: uses ADL with fallback on generic impl
> // Proposed: uses ADL with fallback on generic impl
>
> // Natural method
> std::swap(a, b);
> // C++14: forces generic impl (usually by accident)
> // Proposed: uses ADL with fallback on generic impl
>
> // Force generic impl
> std::no_adl::swap(a, b);
> // C++14: n/a
> // Proposed: forces generic impl (explicitly)
>
> As you can see, the natural and simple way of using swap - by saying "std=
::swap(a,
> b);" - Just Works; you automatically get an ADL-powered search for the
> most optimized swap implementation, falling back on the generic
> implementation.
>
> The same pattern would work for any function that could benefit from
> ADL-found specializations. There would be no need for the kind of dance
> N4183 proposes - with std::pointer_from and std::do_pointer_from, etc.;
> you only need one name. Existing code that specializes swap (in the liter=
al
> sense, by actually creating a specialization in namespace std) would also
> still work.
>
> The only "gotcha" is that the behaviour of code that now uses the
> qualified call "std::swap(a, b);" would change. However, I would argue
> that this isn't really a problem, because virtually all uses of a qualifi=
ed
> call in generic code are almost certainly mistakes. At best, it's harmles=
s
> (for built-in types and std types), but at worst it's picking a
> non-optimized swap implementation. In the astronomically-rare case where
> you *really*, *specifically* want the generic implementation even when a
> specialized implementation exists, you do have that option (by saying "st=
d::no_adl::swap(a,
> b);", which is also self-documenting).
>
> Has this idea been floated before? What was the consensus?
>
> --
>
> ---
> You received this message because you are subscribed to the Google Groups
> "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> Visit this group at
> http://groups.google.com/a/isocpp.org/group/std-proposals/.
>
--=20
---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.
--001a113fb64ee452eb050c899f18
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">There is more to using declaration that meets the eye here=
..=C2=A0 The using declaration makes the function available for regular look=
up at the location where the declaration happens, which is effectively an A=
DL-enabler.=C2=A0 Using the example of 'std::swap', when the user d=
oes:<br><br>struct T {<br>=C2=A0 =C2=A0 U member;<br>=C2=A0 =C2=A0 void swa=
p(T & other) {<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0using ::std::swap;<=
br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0swap(member, other.member);<br>=C2=A0 =
=C2=A0 }<div>};<br><br>The using declaration brings ::std::swap (free funct=
ion) into the scope of the declaration, in doing so it provides a default i=
mplementation if there is no overload for 'swap' taking two 'U&=
#39; object, but more importantly it *enables* ADL. If you remove that usin=
g declaration, regarless of whether there is an overload of 'swap' =
that could be found by ADL for the type 'U', it will fail to compil=
e. =C2=A0<br><br>Why? Without the local declaration introduced by 'usin=
g ::std::swap', normal lookup will find member 'T::swap' and it=
won't attempt ADL at all.=C2=A0 I honestly believe that more emphasis =
should be placed in teaching this particular</div><div><br></div><div>There=
are already two comments in three emails on this topic that mention someth=
ing in the lines of *the dreaded "using namespace std"*; yes, the=
y are dreaded, but more than that, they are not even a solution to the prob=
lem as they don't enable ADL. The symbols in the used namespace will be=
visible in an enclosing namespace, if normal lookup finds anything with th=
at name other than a free function before hitting that, ADL will not kick i=
n.<br><br>I have discussed this problem in the past with different people, =
including Dietmar Kh=C3=BCl, who might have been the first to suggest that =
the problem is that we have built a mechanism with two overlapping interfac=
es.=C2=A0 In the same way that NVI suggests separating the user interface (=
public part of a class) with the extension interface (virtual member functi=
ons), we should have provided two interfaces.=C2=A0 The main problem is tha=
t this ship has sailed, long ago.<br><br>When reading your proposal I see a=
n attempt to get something similar to this, that does not require the intro=
duction of a different name, since the user interface (::std::swap) and the=
implementation (::std::no_adl::swap) differ in the namespace where they li=
ve. =C2=A0<br><br>This is good, with the potential issue that it is a break=
ing change. If today I call ::std::swap, I am explicitly selecting the over=
load that I want, and requesting move/swaps, not asking for any ADL, and th=
e change changes the semantics of my program. Whether this is truly an issu=
e or not is a different thing, and I personally find this acceptable.=C2=A0=
A different option would be to leave what we have as it is, but provide a =
different name for the user interface:<br><br>template <typename T><b=
r>void ::std::do_swap(T& a, T& b) {<br>=C2=A0 =C2=A0 =C2=A0swap(a,b=
); =C2=A0// /no 'using ::std::swap needed here, we are inside ::std<br>=
}<br><br>All existing code would use the old style and have the old behavio=
r.=C2=A0 New user implementations of 'swap' and use fully qualified=
'do_swap' ('adl_swap'?):<br><br>struct T {<br>=C2=A0 =C2=
=A0 U member;<br>=C2=A0 =C2=A0 void swap(T & other) { ::std::do_swap(me=
mber, other.member); }<br>};<br>void swap(T& a, T& b) { ::std::do_s=
wap(a.member, b.member); }</div><div><br></div><div>This goes a bit more in=
the lines of David Krauss' suggestion of having an 'adl' (rath=
er than a 'no_adl') namespace. It imposes a higher cost on the user=
to ensure that the behavior of existing code does not change in the proces=
s.<br><br>Whatever the option taken for the existing functions is, I would =
suggest that we avoid making the same mistake of merging the user/extension=
interfaces the same for newer components.=C2=A0 And more than that, we sho=
uld make sure that new comers into the language are correctly taught that u=
sing declarations (not directives!) are ADL enablers even if we provide a s=
implification of the use case and this is no longer a problem within the st=
andard library.<br><br>=C2=A0 =C2=A0 David<br><br></div></div><div class=3D=
"gmail_extra"><br><div class=3D"gmail_quote">On Tue, Jan 13, 2015 at 12:22 =
AM, Mark A. Gibbs <span dir=3D"ltr"><<a href=3D"mailto:indi.in.the.wired=
@gmail.com" target=3D"_blank">indi.in.the.wired@gmail.com</a>></span> wr=
ote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border=
-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">Has anyone ever pro=
posed using a sub-namespace to solve the ADL problem?<br><br>Right now, thi=
ngs like <span style=3D"font-family:courier new,monospace">std::swap()</spa=
n> are kinda clunky to use properly, because the generic implementation is =
in <span style=3D"font-family:courier new,monospace">std</span>. That means=
when you say "<span style=3D"font-family:courier new,monospace">std::=
swap(x, y);</span>", you are saying "I want the generic implement=
ation of swap", which rules out using specialized implementations (tha=
t aren't in <span style=3D"font-family:courier new,monospace">std</span=
>). The solution right now is to say "<span style=3D"font-family:couri=
er new,monospace">using std::swap; swap(x, y);</span>", which allows A=
DL to select a specialized implementation if available, (ie, if one exists =
in the same namespace as the declaration of the type of <span style=3D"font=
-family:courier new,monospace">x</span> and <span style=3D"font-family:cour=
ier new,monospace">y</span>) and fall back on the generic implementation.<s=
pan style=3D"color:#080"><br></span><code></code><br>But writing "<spa=
n style=3D"font-family:courier new,monospace">using std::func; func(???);</=
span>" to use every "<span style=3D"font-family:courier new,monos=
pace">std::func()</span>" that leverages ADL is verbose and error-pron=
e, and explaining to beginners why it's necessary - especially at early=
stages - is a pain. As more and more non-member functions intended to be u=
sed with ADL get added - <span style=3D"font-family:courier new,monospace">=
std::size()</span>, <span style=3D"font-family:courier new,monospace">std::=
empty()</span>, and also see numerous proposals like N4183 - it's just =
going to get worse. Every non-trivial generic function body is going to sta=
rt to look like this:<br><br><div style=3D"background-color:rgb(250,250,250=
);border-color:rgb(187,187,187);border-style:solid;border-width:1px;word-wr=
ap:break-word"><code><div><span style=3D"color:#008">auto</span><span style=
=3D"color:#000"> foo</span><span style=3D"color:#660">(...)</span><span sty=
le=3D"color:#000"><br></span><span style=3D"color:#660">{</span><span style=
=3D"color:#000"><br>=C2=A0 </span><span style=3D"color:#008">using</span><s=
pan style=3D"color:#000"> std</span><span style=3D"color:#660">::</span><sp=
an style=3D"color:#000">swap</span><span style=3D"color:#660">;</span><span=
style=3D"color:#000"><br>=C2=A0 </span><span style=3D"color:#008">using</s=
pan><span style=3D"color:#000"> std</span><span style=3D"color:#660">::</sp=
an><span style=3D"color:#008">begin</span><span style=3D"color:#660">;</spa=
n><span style=3D"color:#000"><br>=C2=A0 </span><span style=3D"color:#008">u=
sing</span><span style=3D"color:#000"> std</span><span style=3D"color:#660"=
>::</span><span style=3D"color:#008">end</span><span style=3D"color:#660">;=
</span><span style=3D"color:#000"><br>=C2=A0 </span><span style=3D"color:#0=
08">using</span><span style=3D"color:#000"> std</span><span style=3D"color:=
#660">::</span><span style=3D"color:#000">size</span><span style=3D"color:#=
660">;</span><span style=3D"color:#000"><br>=C2=A0 </span><span style=3D"co=
lor:#008">using</span><span style=3D"color:#000"> std</span><span style=3D"=
color:#660">::</span><span style=3D"color:#000">empty</span><span style=3D"=
color:#660">;</span><span style=3D"color:#000"><br>=C2=A0 </span><span styl=
e=3D"color:#008">using</span><span style=3D"color:#000"> std</span><span st=
yle=3D"color:#660">::</span><span style=3D"color:#000">data</span><span sty=
le=3D"color:#660">;</span><span style=3D"color:#000"><br>=C2=A0 </span><spa=
n style=3D"color:#800">// ...</span><span style=3D"color:#000"><br>=C2=A0 <=
br>=C2=A0 </span><span style=3D"color:#800">// actual function body</span><=
span style=3D"color:#000"><br></span><span style=3D"color:#660">}</span><sp=
an style=3D"color:#000"><br></span></div></code></div><br>(Either that or t=
he dreaded "<span style=3D"font-family:courier new,monospace">using na=
mespace std;</span>".)<br><br>I have been musing over possibilities to=
avoid all this mess and have <span style=3D"font-family:courier new,monosp=
ace">std::func()</span> use ADL to select a specialized implementation then=
fall back on a generic implementation.<br><br>I saw <a href=3D"http://eric=
niebler.com/2014/10/21/customization-point-design-in-c11-and-beyond/" targe=
t=3D"_blank">Eric Neibler's post about "customization points"=
</a>, where he offered a clever solution using a global function object, bu=
t that struck me as over-engineering what should be a simple problem. It al=
so doesn't easily allow <i>forcing</i> the use of the generic implement=
ation, if that's what you really want.<br><br>It seems to me all we rea=
lly need is a special namespace for generic implementations, so the functio=
n in namespace <span style=3D"font-family:courier new,monospace">std</span>=
uses ADL to search for a specialized implementation then falls back on the=
generic implementation.<br><br>For example (I'm going to be using swap=
since that's the function most people associate with the ADL problem, =
but I'm going to simplify it for readability, ignoring exception specif=
ications and so on):<br><br><div style=3D"background-color:rgb(250,250,250)=
;border-color:rgb(187,187,187);border-style:solid;border-width:1px;word-wra=
p:break-word"><code><div><span style=3D"color:#008">namespace</span><span s=
tyle=3D"color:#000"> std </span><span style=3D"color:#660">{</span><span st=
yle=3D"color:#000"><br><br></span><span style=3D"color:#008">namespace</spa=
n><span style=3D"color:#000"> no_adl </span><span style=3D"color:#660">{</s=
pan><span style=3D"color:#000"><br><br></span><span style=3D"color:#800">//=
Generic (fallback) implementation</span><span style=3D"color:#000"><br></s=
pan><span style=3D"color:#008">template</span><span style=3D"color:#000"> <=
/span><span style=3D"color:#660"><</span><span style=3D"color:#008">type=
name</span><span style=3D"color:#000"> T</span><span style=3D"color:#660">&=
gt;</span><span style=3D"color:#000"><br></span><span style=3D"color:#008">=
void</span><span style=3D"color:#000"> swap</span><span style=3D"color:#660=
">(</span><span style=3D"color:#000">T</span><span style=3D"color:#660">&am=
p;</span><span style=3D"color:#000"> a</span><span style=3D"color:#660">,</=
span><span style=3D"color:#000"> T</span><span style=3D"color:#660">&</=
span><span style=3D"color:#000"> b</span><span style=3D"color:#660">)</span=
><span style=3D"color:#000"><br></span><span style=3D"color:#660">{</span><=
span style=3D"color:#000"><br>=C2=A0 </span><span style=3D"color:#008">auto=
</span><span style=3D"color:#000"> t </span><span style=3D"color:#660">=3D<=
/span><span style=3D"color:#000"> move</span><span style=3D"color:#660">(</=
span><span style=3D"color:#000">a</span><span style=3D"color:#660">);</span=
><span style=3D"color:#000"><br>=C2=A0 a </span><span style=3D"color:#660">=
=3D</span><span style=3D"color:#000"> move</span><span style=3D"color:#660"=
>(</span><span style=3D"color:#000">b</span><span style=3D"color:#660">);</=
span><span style=3D"color:#000"><br>=C2=A0 b </span><span style=3D"color:#6=
60">=3D</span><span style=3D"color:#000"> move</span><span style=3D"color:#=
660">(</span><span style=3D"color:#000">t</span><span style=3D"color:#660">=
);</span><span style=3D"color:#000"><br></span><span style=3D"color:#660">}=
</span><span style=3D"color:#000"><br><br></span><span style=3D"color:#660"=
>}</span><span style=3D"color:#000"> </span><span style=3D"color:#800">// n=
amespace no_adl</span><span style=3D"color:#000"><br><br></span><span style=
=3D"color:#800">// Dispatch function</span><span style=3D"color:#000"><br><=
/span><span style=3D"color:#008">template</span><span style=3D"color:#000">=
</span><span style=3D"color:#660"><</span><span style=3D"color:#008">ty=
pename</span><span style=3D"color:#000"> T</span><span style=3D"color:#660"=
>></span><span style=3D"color:#000"><br></span><span style=3D"color:#008=
">void</span><span style=3D"color:#000"> swap</span><span style=3D"color:#6=
60">(</span><span style=3D"color:#000">T</span><span style=3D"color:#660">&=
amp;</span><span style=3D"color:#000"> a</span><span style=3D"color:#660">,=
</span><span style=3D"color:#000"> T</span><span style=3D"color:#660">&=
</span><span style=3D"color:#000"> b</span><span style=3D"color:#660">)</sp=
an><span style=3D"color:#000"><br></span><span style=3D"color:#660">{</span=
><span style=3D"color:#000"><br>=C2=A0 </span><span style=3D"color:#008">us=
ing</span><span style=3D"color:#000"> no_adl</span><span style=3D"color:#66=
0">::</span><span style=3D"color:#000">swap</span><span style=3D"color:#660=
">;</span><span style=3D"color:#000"><br>=C2=A0 swap</span><span style=3D"c=
olor:#660">(</span><span style=3D"color:#000">a</span><span style=3D"color:=
#660">,</span><span style=3D"color:#000"> b</span><span style=3D"color:#660=
">);</span><span style=3D"color:#000"><br></span><span style=3D"color:#660"=
>}</span><span style=3D"color:#000"><br><br></span><span style=3D"color:#80=
0">// other swap specializations in namespace std</span><span style=3D"colo=
r:#000"><br></span><span style=3D"color:#800">// for example...</span><span=
style=3D"color:#000"><br></span><span style=3D"color:#008">void</span><spa=
n style=3D"color:#000"> swap</span><span style=3D"color:#660">(</span><span=
style=3D"color:#000">thread</span><span style=3D"color:#660">&</span><=
span style=3D"color:#000"> a</span><span style=3D"color:#660">,</span><span=
style=3D"color:#000"> thread</span><span style=3D"color:#660">&</span>=
<span style=3D"color:#000"> b</span><span style=3D"color:#660">)</span><spa=
n style=3D"color:#000"><br></span><span style=3D"color:#660">{</span><span =
style=3D"color:#000"><br>=C2=A0 a</span><span style=3D"color:#660">.</span>=
<span style=3D"color:#000">swap</span><span style=3D"color:#660">(</span><s=
pan style=3D"color:#000">b</span><span style=3D"color:#660">);</span><span =
style=3D"color:#000"><br></span><span style=3D"color:#660">}</span><span st=
yle=3D"color:#000"><br><br></span><span style=3D"color:#008">template</span=
><span style=3D"color:#000"> </span><span style=3D"color:#660"><</span><=
span style=3D"color:#008">typename</span><span style=3D"color:#000"> T</spa=
n><span style=3D"color:#660">,</span><span style=3D"color:#000"> </span><sp=
an style=3D"color:#008">typename</span><span style=3D"color:#000"> </span><=
span style=3D"color:#606">Alloc</span><span style=3D"color:#660">></span=
><span style=3D"color:#000"><br></span><span style=3D"color:#008">void</spa=
n><span style=3D"color:#000"> swap</span><span style=3D"color:#660">(</span=
><span style=3D"color:#000">vector</span><span style=3D"color:#660"><</s=
pan><span style=3D"color:#000">T</span><span style=3D"color:#660">,</span><=
span style=3D"color:#000"> </span><span style=3D"color:#606">Alloc</span><s=
pan style=3D"color:#660">>&</span><span style=3D"color:#000"> a</spa=
n><span style=3D"color:#660">,</span><span style=3D"color:#000"> vector</sp=
an><span style=3D"color:#660"><</span><span style=3D"color:#000">T</span=
><span style=3D"color:#660">,</span><span style=3D"color:#000"> </span><spa=
n style=3D"color:#606">Alloc</span><span style=3D"color:#660">>&</sp=
an><span style=3D"color:#000"> b</span><span style=3D"color:#660">)</span><=
span style=3D"color:#000"><br></span><span style=3D"color:#660">{</span><sp=
an style=3D"color:#000"><br>=C2=A0 a</span><span style=3D"color:#660">.</sp=
an><span style=3D"color:#000">swap</span><span style=3D"color:#660">(</span=
><span style=3D"color:#000">b</span><span style=3D"color:#660">);</span><sp=
an style=3D"color:#000"><br></span><span style=3D"color:#660">}</span><span=
style=3D"color:#000"><br><br></span><span style=3D"color:#660">}</span><sp=
an style=3D"color:#000"> </span><span style=3D"color:#800">// namespace std=
</span><span style=3D"color:#000"><br></span></div></code></div><br>The eff=
ects of this change would be this:<br><br><div style=3D"background-color:rg=
b(250,250,250);border-color:rgb(187,187,187);border-style:solid;border-widt=
h:1px;word-wrap:break-word"><code><div><span style=3D"color:#800">// Curren=
tly recommended method</span><span style=3D"color:#000"><br></span><span st=
yle=3D"color:#008">using</span><span style=3D"color:#000"> std</span><span =
style=3D"color:#660">::</span><span style=3D"color:#000">swap</span><span s=
tyle=3D"color:#660">;</span><span style=3D"color:#000"><br>swap</span><span=
style=3D"color:#660">(</span><span style=3D"color:#000">a</span><span styl=
e=3D"color:#660">,</span><span style=3D"color:#000"> b</span><span style=3D=
"color:#660">);</span><span style=3D"color:#000"><br></span><span style=3D"=
color:#800">// C++14: =C2=A0 =C2=A0uses ADL with fallback on generic impl</=
span><span style=3D"color:#000"><br></span><span style=3D"color:#800">// Pr=
oposed: uses ADL with fallback on generic impl</span><span style=3D"color:#=
000"><br><br></span><span style=3D"color:#800">// Natural method</span><spa=
n style=3D"color:#000"><br>std</span><span style=3D"color:#660">::</span><s=
pan style=3D"color:#000">swap</span><span style=3D"color:#660">(</span><spa=
n style=3D"color:#000">a</span><span style=3D"color:#660">,</span><span sty=
le=3D"color:#000"> b</span><span style=3D"color:#660">);</span><span style=
=3D"color:#000"><br></span><span style=3D"color:#800">// C++14: =C2=A0 =C2=
=A0forces generic impl (usually by accident)</span><span style=3D"color:#00=
0"><br></span><span style=3D"color:#800">// Proposed: uses ADL with fallbac=
k on generic impl</span><span style=3D"color:#000"><br><br></span><span sty=
le=3D"color:#800">// Force generic impl</span><span style=3D"color:#000"><b=
r>std</span><span style=3D"color:#660">::</span><span style=3D"color:#000">=
no_adl</span><span style=3D"color:#660">::</span><span style=3D"color:#000"=
>swap</span><span style=3D"color:#660">(</span><span style=3D"color:#000">a=
</span><span style=3D"color:#660">,</span><span style=3D"color:#000"> b</sp=
an><span style=3D"color:#660">);</span><span style=3D"color:#000"><br></spa=
n><span style=3D"color:#800">// C++14: =C2=A0 =C2=A0n/a</span><span style=
=3D"color:#000"><br></span><span style=3D"color:#800">// Proposed: forces g=
eneric impl (explicitly)</span><span style=3D"color:#000"><br></span></div>=
</code></div><br>As you can see, the natural and simple way of using swap -=
by saying "<span style=3D"font-family:courier new,monospace">std::swa=
p(a, b);</span>" - Just Works; you automatically get an ADL-powered se=
arch for the most optimized swap implementation, falling back on the generi=
c implementation.<br><br>The same pattern would work for any function that =
could benefit from ADL-found specializations. There would be no need for th=
e kind of dance N4183 proposes - with <span style=3D"font-family:courier ne=
w,monospace">std::pointer_from</span> and <span style=3D"font-family:courie=
r new,monospace">std::do_pointer_from</span>, etc.; you only need one name.=
Existing code that specializes swap (in the literal sense, by actually cre=
ating a specialization in namespace <span style=3D"font-family:courier new,=
monospace">std</span>) would also still work.<br><br>The only "gotcha&=
quot; is that the behaviour of code that now uses the qualified call "=
<span style=3D"font-family:courier new,monospace">std::swap(a, b);</span>&q=
uot; would change. However, I would argue that this isn't really a prob=
lem, because virtually all uses of a qualified call in generic code are alm=
ost certainly mistakes. At best, it's harmless (for built-in types and =
std types), but at worst it's picking a non-optimized swap implementati=
on. In the astronomically-rare case where you <i>really</i>, <i>specificall=
y</i> want the generic implementation even when a specialized implementatio=
n exists, you do have that option (by saying "<span style=3D"font-fami=
ly:courier new,monospace">std::no_adl::swap(a, b);</span>", which is a=
lso self-documenting).<br><br>Has this idea been floated before? What was t=
he consensus?<span class=3D"HOEnZb"><font color=3D"#888888"><br></font></sp=
an></div><span class=3D"HOEnZb"><font color=3D"#888888">
<p></p>
-- <br>
<br>
--- <br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_=
blank">std-proposals+unsubscribe@isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/" target=3D"_blank">http://groups.google.com/a/isocpp.org/gro=
up/std-proposals/</a>.<br>
</font></span></blockquote></div><br></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
--001a113fb64ee452eb050c899f18--
.
Author: "Mark A. Gibbs" <indi.in.the.wired@gmail.com>
Date: Tue, 20 Jan 2015 22:31:50 -0800 (PST)
Raw View
------=_Part_1023_484568925.1421821910686
Content-Type: multipart/alternative;
boundary="----=_Part_1024_891933051.1421821910686"
------=_Part_1024_891933051.1421821910686
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Tuesday, 13 January 2015 00:42:40 UTC-5, David Krauss wrote:
>
> How about a namespace adl instead?
>
I thought about this, too, but I went the "no_adl" namespace direction=20
because the "adl" namespace direction doesn't really solve anything. All it=
=20
does in the end is save you a few keystrokes from "using std::swap; swap(a,=
=20
b);" to "std::adl::swap(a, b);"... and it doesn't even really save all that=
=20
much. And the original problem remains.
I think I may have made a mistake focusing too much on the ADL problem,=20
because what I'm getting at here isn't *just* about avoiding/controlling=20
ADL - or even primarily about that. (It's actually somewhat orthogonal to=
=20
what's discussed in N3490, the paper Ville Voutilainen linked to. A feature=
=20
like the one discussed in that paper could actually be useful in tandem=20
with what I'm talking about here.) What I'm after is a consistent interface=
=20
to functions that benefit from customization via ADL or=20
specialization/overload. It's less about ADL itself, and more about what=20
Niebler called "customization points". It's also what David Rodr=C3=ADguez =
Ibeas=20
is alluding to in the final paragraphs of his comments - though I think he=
=20
put it better when he describes the existing situation as "merging the=20
user/extension interfaces". I suppose you could describe what I'm getting=
=20
at as attempting to separate them, as harmlessly as possible.
Let me demonstrate what I mean. Consider "swap(x, x)" (which I know is a=20
logical no-op, but it allows me to simplify and talk only about a single=20
argument). Right now, calling "std::swap(x, x)" is a bit of a craps=20
shoot... you don't know where your control flow is going to go. And that=20
could change without warning due to something someone else did somewhere=20
else totally unrelated. Yes, technically you know you're going to be=20
calling one of "std::swap(T&, T&)" or "template <> std::swap<T>(T&, T&)",=
=20
but, really, that's only very slightly more certainty than knowing you're=
=20
going to be calling one of "std::swap(T&, T&)" or "template <>=20
std::swap<T>(T&, T&)" or "{namespace of T}::swap(T&, T&)", and it skirts=20
the fact that you don't know whether the swap in std that's being called is=
=20
the generic implementation or a custom implementation (which could be=20
anywhere in the code base).
Suppose x is an instance of:
- int
- std::thread
- boost::gil::image
- some_lib::some_obj
=20
and I asked you to predict where your program is going to go when you call =
"std::swap(x,=20
x)" in each case.
Here's what currently happens when you call it as "std::swap(x, x);":
- specialized impl (std::swap(int&, int&))
- specialized impl (std::swap(std::thread&, std::thread&))
- generic impl
- ???
=20
In the last case, you have no idea what will happen when you call swap. It=
=20
might use the generic three-move swap. But then, tomorrow someone adds a=20
specialization of swap for that type somewhere else in the code base. Or,=
=20
vice versa, it may use a specialization of swap today because the type is a=
=20
non-template, but tomorrow it becomes a template so the swap can no longer=
=20
be a specialization in std and now has to be found via ADL, and code may=20
still compile while silently changing behaviour. (Here I disagree with what=
=20
David Rodr=C3=ADguez Ibeas said about: "If today I call ::std::swap, I am=
=20
explicitly selecting the overload that I want, and requesting move/swaps,=
=20
not asking for any ADL, and the change changes the semantics of my=20
program." I would say that with the current nature of swap, the semantics=
=20
of such a program are already brittle. It's true that you're explicitly=20
selecting an overload/specialization of std::swap, but a third party can=20
change things completely outside of that function and module by=20
adding/removing the specialization in std.)
As it stands, a novice can write a template function that calls "std::swap(=
a,=20
b);", and it would work just fine for one user type that defines a=20
specialization of swap, and fails for another user type that defines a swap=
=20
function it hopes will by found by ADL. That seems to imply that if you=20
really want your type's swap function to be reliably used, you should=20
prefer a specialization of std::swap rather than a swap function in the=20
type's namespace... which is the opposite of what most experts recommend.=
=20
When you're working against the easiest and most logical solution, that's a=
=20
signal to me that something's amiss.
Adding a new namespace "adl" doesn't fix this. If we did things using that=
=20
scheme, calling "std::swap(x, x);" would behave as it does today:
- specialized impl (std::swap(int&, int&))
- specialized impl (std::swap(std::thread&, std::thread&))
- generic impl
- ???
and calling "std::adl::swap(x, x);" (which is the same as "using std::swap;=
=20
swap(x, x);") would give you this:
- specialized impl (std::swap(int&, int&))
- specialized impl (std::swap(std::thread&, std::thread&))
- specialized impl (boost::gil::swap(boost::gil::image&,=20
boost::gil::image&))
- specialized impl (via specialization or adl; if none exists, generic=
=20
impl)
As you can see, the confusion with "std::swap()" (and the original problem=
=20
of accidentally calling it qualified when you really want ADL) still=20
remains. In other words, nothing is really fixed. (Pretty much the same=20
applies to David Rodr=C3=ADguez Ibeas's "std::do_swap" scheme.)
Here's why I leaned toward a "no_adl" namespace. If there were a "no_adl"=
=20
namespace, and the only thing in it was the generic (three-move) swap, and=
=20
calling "std::swap(a, b)" was equivalent to "using std::no_adl::swap;=20
swap(a, b);", then...
With the namespace no_adl scheme, here's what you get calling "std::swap(x,=
=20
x);":
- specialized impl (std::swap(int&, int&))
- specialized impl (std::swap(std::thread&, std::thread&))
- specialized impl (boost::gil::swap(boost::gil::image&,=20
boost::gil::image&))
- specialized impl (via specialization or adl; if none exists, generic=
=20
impl)
and here's what you get calling "std::no_adl::swap(x, x);":
- generic impl
- generic impl
- generic impl
- generic impl
As you can see, that's much more consistent.
If we did things this way, then for any type you can always explicitly=20
request:
- the generic implementation (via "std::no_adl::swap(a, b);"), which may=
=20
not work for all types (just as the current qualified call to swap may n=
ot=20
work for all types - some types that can't be swapped by the generic swa=
p=20
have to "specialize" swap by ADL because they're templates);
- a custom implementation (assuming it's customized the right way - as=
=20
experts recommend - by defining a swap function in the type's namespace=
=20
rather than specializing std::swap, via "<no 'using std::swap;' or=20
'using std::no_adl::swap;'> swap(a, b);");
- or you can request the "best" implementation - custom if it exists,=20
generic if not - via "std::swap(a, b);".
You don't get all three options with the namespace adl or do_swap schemes=
=20
(and you don't get it consistently with the status quo). And the "best"=20
option - the one you'll probably want pretty much all of the time - is also=
=20
the easiest. And there's no more benefit from specializing std::swap rather=
=20
than just making a swap function in the type's namespace - what is right=20
and what is easy become the same.
That's what I'm getting at - not so much controlling/avoiding ADL as=20
getting consistent and predictable behaviour when using facilities that are=
=20
meant to be extended/customized (whether via ADL or template=20
specialization). The namespace "adl" does nothing to solve this problem -=
=20
it does nothing at all but save you a few keystrokes.
Maybe "no_adl" isn't the right name for the namespace I'm talking about -=
=20
maybe "generic" (std::generic::swap())? Or "force_generic" (
std::force_generic::swap())? The idea is that "std::foo" is a consistent=20
interface to something that has a generic interface ("std::???::foo"), but=
=20
that can be customized/extended/specialized/optimized - by *any* technique,=
=20
whether it's using ADL or specializing.
Right now, "std::foo" for user types uses the generic implementation or a=
=20
template specialization... and you don't know which, and it may change=20
unexpectedly because of code somewhere else. What I'm suggesting is that we=
=20
just embrace that uncertainty and say that "std::foo" will always get you=
=20
the best possible implementation of "foo", which includes not only=20
specializations but also things found via ADL. And, as a corollary, "
std::???::foo" will always get you the standard, generic implementation of=
=20
"foo", which may not be optimal (or even legal), but there it is if you=20
really want it (which isn't the case today).
Incidentally, regarding the concerns about changing the behaviour of swap,=
=20
I'd point out that's already been done once - when it went from the 3 copy=
=20
to the 3 move implementation - and also that the current behaviour of swap=
=20
is already unpredictable. You don't *really* know where it's going to go in=
=20
the general case, even without considering ADL - it could be specialized=20
elsewhere in the code base.
But perhaps the strongest argument for a breaking change like this is that=
=20
we now have the awkward situation where a type that is Swappable (according=
=20
to =C2=A717.6.3.2) may not actually work when calling std::swap(). ("This t=
ype=20
is Swappable, but it's not std::swappable.") The description for std::swap(=
)=20
is therefore not "swaps two values", but rather "swaps two values... if and=
=20
only if the type of the two values is either a fundamental type or a type=
=20
in namespace std, or someone has specialized template swap() for that=20
type". Personally, I'd rather the simple case where "std::swap() swaps any=
=20
two Swappable values", period (and there's std::no_adl?::swap() as the=20
generic implementation if I really want it).
Even if it's too late to fix all the existing ADL-customizable functions=20
like swap - which I don't really agree with - future ADL-customizable=20
functions (like std::size(), std::empty(), and so on) could benefit from=20
this. I think the main benefit of the "no_adl" scheme in particular is that=
=20
it is a fairly harmless "fix" for functions that already exist (like swap),=
=20
but it's also a pretty nice scheme on its own - there's no need for clunky=
=20
prefixes like "do_", to customize "std::foo", you just write a foo function=
=20
with the right signature in the type's namespace and it just works.
--=20
---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.
------=_Part_1024_891933051.1421821910686
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Tuesday, 13 January 2015 00:42:40 UTC-5, David Krauss =
wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8=
ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div style=3D"word-wrap:=
break-word">How about a namespace <font face=3D"Courier">adl</font> instead=
?</div></blockquote><div><br> I thought about this, too, but I went th=
e "<span style=3D"font-family: courier new,monospace;">no_adl</span>" names=
pace direction because the "<span style=3D"font-family: courier new,monospa=
ce;">adl</span>" namespace direction doesn't really solve anything. All it =
does in the end is save you a few keystrokes from "<span style=3D"font-fami=
ly: courier new,monospace;">using std::swap; swap(a, b);</span>" to "<span =
style=3D"font-family: courier new,monospace;">std::adl::swap(a, b);</span>"=
.... and it doesn't even really save all that much. And the original problem=
remains.<br><br>I think I may have made a mistake focusing too much on the=
ADL problem, because what I'm getting at here isn't <i>just</i> about avoi=
ding/controlling ADL - or even primarily about that. (It's actually somewha=
t orthogonal to what's discussed in N3490, the paper Ville Voutilainen link=
ed to. A feature like the one discussed in that paper could actually be use=
ful in tandem with what I'm talking about here.) What I'm after is a consis=
tent interface to functions that benefit from customization via ADL or spec=
ialization/overload. It's less about ADL itself, and more about what Nieble=
r called "customization points". It's also what David Rodr=C3=ADguez Ibeas =
is alluding to in the final paragraphs of his comments - though I think he =
put it better when he describes the existing situation as "merging the user=
/extension interfaces". I suppose you could describe what I'm getting at as=
attempting to separate them, as harmlessly as possible.<br><br>Let me demo=
nstrate what I mean. Consider "<span style=3D"font-family: courier new,mono=
space;">swap(x, x)</span>" (which I know is a logical no-op, but it allows =
me to simplify and talk only about a single argument). Right now, calling "=
<span style=3D"font-family: courier new,monospace;">std::swap(x, x)</span>"=
is a bit of a craps shoot... you don't know where your control flow is goi=
ng to go. And that could change without warning due to something someone el=
se did somewhere else totally unrelated. Yes, technically you know you're g=
oing to be calling one of "<span style=3D"font-family: courier new,monospac=
e;">std::swap(T&, T&)</span>" or "<span style=3D"font-family: couri=
er new,monospace;">template <> std::swap<T>(T&, T&)</sp=
an>", but, really, that's only very slightly more certainty than knowing yo=
u're going to be calling one of "<span style=3D"font-family: courier new,mo=
nospace;">std::swap(T&, T&)</span>" or "<span style=3D"font-family:=
courier new,monospace;">template <> std::swap<T>(T&, T&=
;)</span>" or "<span style=3D"font-family: courier new,monospace;">{namespa=
ce of T}::swap(T&, T&)</span>", and it skirts the fact that you don=
't know whether the swap in std that's being called is the generic implemen=
tation or a custom implementation (which could be anywhere in the code base=
).<br><br>Suppose x is an instance of:<br><ul><li><span style=3D"font-famil=
y: courier new,monospace;">int</span></li><li><span style=3D"font-family: c=
ourier new,monospace;">std::thread</span></li><li><span style=3D"font-famil=
y: courier new,monospace;">boost::gil::image</span></li><li><span style=3D"=
font-family: courier new,monospace;">some_lib::some_obj</span><br></li></ul=
>and I asked you to predict where your program is going to go when you call=
"<span style=3D"font-family: courier new,monospace;">std::swap(x, x)</span=
>" in each case.<br><br>Here's what currently happens when you call it as "=
<span style=3D"font-family: courier new,monospace;">std::swap(x, x);</span>=
":<br><ul><li>specialized impl (<span style=3D"font-family: courier new,mon=
ospace;">std::swap(int&, int&)</span>)</li><li>specialized impl (<s=
pan style=3D"font-family: courier new,monospace;">std::swap(std::thread&=
;, std::thread&)</span>)</li><li>generic impl</li><li>???<br></li></ul>=
In the last case, you have no idea what will happen when you call swap. It =
might use the generic three-move swap. But then, tomorrow someone adds a sp=
ecialization of swap for that type somewhere else in the code base. Or, vic=
e versa, it may use a specialization of swap today because the type is a no=
n-template, but tomorrow it becomes a template so the swap can no longer be=
a specialization in std and now has to be found via ADL, and code may stil=
l compile while silently changing behaviour. (Here I disagree with what Dav=
id Rodr=C3=ADguez Ibeas said about: "If today I call ::std::swap, I am expl=
icitly selecting the overload that I want, and requesting move/swaps, not a=
sking for any ADL, and the change changes the semantics of my program." I w=
ould say that with the current nature of swap, the semantics of such a prog=
ram are already brittle. It's true that you're explicitly selecting an over=
load/specialization of <span style=3D"font-family: courier new,monospace;">=
std::swap</span>, but a third party can change things completely outside of=
that function and module by adding/removing the specialization in <span st=
yle=3D"font-family: courier new,monospace;">std</span>.)<br><br>As it stand=
s, a novice can write a template function that calls "<span style=3D"font-f=
amily: courier new,monospace;">std::swap(a, b);</span>", and it would work =
just fine for one user type that defines a specialization of swap, and fail=
s for another user type that defines a swap function it hopes will by found=
by ADL. That seems to imply that if you really want your type's swap funct=
ion to be reliably used, you should prefer a specialization of <span style=
=3D"font-family: courier new,monospace;">std::swap</span> rather than a swa=
p function in the type's namespace... which is the opposite of what most ex=
perts recommend. When you're working against the easiest and most logical s=
olution, that's a signal to me that something's amiss.<br><br>Adding a new =
namespace "<span style=3D"font-family: courier new,monospace;">adl</span>" =
doesn't fix this. If we did things using that scheme, calling "<span style=
=3D"font-family: courier new,monospace;">std::swap(x, x);</span>" would beh=
ave as it does today:<br><ul><li>specialized impl (<span style=3D"font-fami=
ly: courier new,monospace;">std::swap(int&, int&)</span>)</li><li>s=
pecialized impl (<span style=3D"font-family: courier new,monospace;">std::s=
wap(std::thread&, std::thread&)</span>)</li><li>generic impl</li><l=
i>???</li></ul>and calling "std::adl::swap(x, x);" (which is the same as "u=
sing std::swap; swap(x, x);") would give you this:<br><ul><li>specialized i=
mpl (<span style=3D"font-family: courier new,monospace;">std::swap(int&=
, int&)</span>)</li><li>specialized impl (<span style=3D"font-family: c=
ourier new,monospace;">std::swap(std::thread&, std::thread&)</span>=
)</li><li>specialized impl (<span style=3D"font-family: courier new,monospa=
ce;">boost::gil::swap(boost::gil::image&, boost::gil::image&)</span=
>)</li><li>specialized impl (via specialization or adl; if none exists, gen=
eric impl)</li></ul>As you can see, the confusion with "<span style=3D"font=
-family: courier new,monospace;">std::swap()</span>" (and the original prob=
lem of accidentally calling it qualified when you really want ADL) still re=
mains. In other words, nothing is really fixed. (Pretty much the same appli=
es to David Rodr=C3=ADguez Ibeas's "<span style=3D"font-family: courier new=
,monospace;">std::do_swap</span>" scheme.)<br><br>Here's why I leaned towar=
d a "<span style=3D"font-family: courier new,monospace;">no_adl</span>" nam=
espace. If there were a "<span style=3D"font-family: courier new,monospace;=
">no_adl</span>" namespace, and the only thing in it was the generic (three=
-move) swap, and calling "<span style=3D"font-family: courier new,monospace=
;">std::swap(a, b)</span>" was equivalent to "<span style=3D"font-family: c=
ourier new,monospace;">using std::no_adl::swap; swap(a, b);</span>", then..=
..<br><br>With the namespace <span style=3D"font-family: courier new,monospa=
ce;">no_adl</span> scheme, here's what you get calling "<span style=3D"font=
-family: courier new,monospace;">std::swap(x, x);</span>":<br><ul><li>speci=
alized impl (<span style=3D"font-family: courier new,monospace;">std::swap(=
int&, int&)</span>)</li><li>specialized impl (<span style=3D"font-f=
amily: courier new,monospace;">std::swap(std::thread&, std::thread&=
)</span>)</li><li>specialized impl (<span style=3D"font-family: courier new=
,monospace;">boost::gil::swap(boost::gil::image&, boost::gil::image&=
;)</span>)</li><li>specialized impl (via specialization or adl; if none exi=
sts, generic impl)</li></ul>and here's what you get calling "<span style=3D=
"font-family: courier new,monospace;">std::no_adl::swap(x, x);</span>":<br>=
<ul><li>generic impl</li><li>generic impl</li><li>generic impl</li><li>gene=
ric impl</li></ul>As you can see, that's much more consistent.<br><br>If we=
did things this way, then for any type you can always explicitly request:<=
br><ul><li>the generic implementation (via "<span style=3D"font-family: cou=
rier new,monospace;">std::no_adl::swap(a, b);</span>"), which may not work =
for all types (just as the current qualified call to swap may not work for =
all types - some types that can't be swapped by the generic swap have to "s=
pecialize" swap by ADL because they're templates);</li><li>a custom impleme=
ntation (assuming it's customized the right way - as experts recommend - by=
defining a swap function in the type's namespace rather than specializing =
std::swap, via "<span style=3D"font-family: courier new,monospace;"><no =
'using std::swap;' or 'using std::no_adl::swap;'> swap(a, b);</span>");<=
/li><li>or you can request the "best" implementation - custom if it exists,=
generic if not - via "<span style=3D"font-family: courier new,monospace;">=
std::swap(a, b);</span>".</li></ul>You don't get all three options with the=
namespace <span style=3D"font-family: courier new,monospace;">adl</span> o=
r <span style=3D"font-family: courier new,monospace;">do_swap</span> scheme=
s (and you don't get it consistently with the status quo). And the "best" o=
ption - the one you'll probably want pretty much all of the time - is also =
the easiest. And there's no more benefit from specializing std::swap rather=
than just making a swap function in the type's namespace - what is right a=
nd what is easy become the same.<br><br>That's what I'm getting at - not so=
much controlling/avoiding ADL as getting consistent and predictable behavi=
our when using facilities that are meant to be extended/customized (whether=
via ADL or template specialization). The namespace "<span style=3D"font-fa=
mily: courier new,monospace;">adl</span>" does nothing to solve this proble=
m - it does nothing at all but save you a few keystrokes.<br><br>Maybe "<sp=
an style=3D"font-family: courier new,monospace;">no_adl</span>" isn't the r=
ight name for the namespace I'm talking about - maybe "<span style=3D"font-=
family: courier new,monospace;">generic</span>" (<span style=3D"font-family=
: courier new,monospace;">std::generic::swap()</span>)? Or "<span style=3D"=
font-family: courier new,monospace;">force_generic</span>" (<span style=3D"=
font-family: courier new,monospace;">std::force_generic::swap()</span>)? Th=
e idea is that "<span style=3D"font-family: courier new,monospace;">std::fo=
o</span>" is a consistent interface to something that has a generic interfa=
ce ("<span style=3D"font-family: courier new,monospace;">std::???::foo</spa=
n>"), but that can be customized/extended/specialized/optimized - by *any* =
technique, whether it's using ADL or specializing.<br><br>Right now, "<span=
style=3D"font-family: courier new,monospace;">std::foo</span>" for user ty=
pes uses the generic implementation or a template specialization... and you=
don't know which, and it may change unexpectedly because of code somewhere=
else. What I'm suggesting is that we just embrace that uncertainty and say=
that "<span style=3D"font-family: courier new,monospace;">std::foo</span>"=
will always get you the best possible implementation of "foo", which inclu=
des not only specializations but also things found via ADL. And, as a corol=
lary, "<span style=3D"font-family: courier new,monospace;">std::???::foo</s=
pan>" will always get you the standard, generic implementation of "foo", wh=
ich may not be optimal (or even legal), but there it is if you really want =
it (which isn't the case today).<br><br>Incidentally, regarding the concern=
s about changing the behaviour of swap, I'd point out that's already been d=
one once - when it went from the 3 copy to the 3 move implementation - and =
also that the current behaviour of swap is already unpredictable. You don't=
<i>really</i> know where it's going to go in the general case, even withou=
t considering ADL - it could be specialized elsewhere in the code base.<br>=
<br>But perhaps the strongest argument for a breaking change like this is t=
hat we now have the awkward situation where a type that is Swappable (accor=
ding to =C2=A717.6.3.2) may not actually work when calling <span style=3D"f=
ont-family: courier new,monospace;">std::swap()</span>. ("This type is Swap=
pable, but it's not std::swappable.") The description for <span style=3D"fo=
nt-family: courier new,monospace;">std::swap()</span> is therefore not "swa=
ps two values", but rather "swaps two values... if and only if the type of =
the two values is either a fundamental type or a type in namespace <span st=
yle=3D"font-family: courier new,monospace;">std</span>, or someone has spec=
ialized template <span style=3D"font-family: courier new,monospace;">swap()=
</span> for that type". Personally, I'd rather the simple case where "<span=
style=3D"font-family: courier new,monospace;">std::swap()</span> swaps any=
two Swappable values", period (and there's <span style=3D"font-family: cou=
rier new,monospace;">std::no_adl?::swap()</span> as the generic implementat=
ion if I really want it).<br><br>Even if it's too late to fix all the exist=
ing ADL-customizable functions like swap - which I don't really agree with =
- future ADL-customizable functions (like <span style=3D"font-family: couri=
er new,monospace;">std::size()</span>, <span style=3D"font-family: courier =
new,monospace;">std::empty()</span>, and so on) could benefit from this. I =
think the main benefit of the "<span style=3D"font-family: courier new,mono=
space;">no_adl</span>" scheme in particular is that it is a fairly harmless=
"fix" for functions that already exist (like swap), but it's also a pretty=
nice scheme on its own - there's no need for clunky prefixes like "<span s=
tyle=3D"font-family: courier new,monospace;">do_</span>", to customize "<sp=
an style=3D"font-family: courier new,monospace;">std::foo</span>", you just=
write a foo function with the right signature in the type's namespace and =
it just works.<br></div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_1024_891933051.1421821910686--
------=_Part_1023_484568925.1421821910686--
.
Author: =?UTF-8?Q?R=C3=B3bert_D=C3=A1vid?= <lrdxgm@gmail.com>
Date: Sun, 25 Jan 2015 13:45:36 -0800 (PST)
Raw View
------=_Part_3677_3154893.1422222336682
Content-Type: multipart/alternative;
boundary="----=_Part_3678_1484679123.1422222336682"
------=_Part_3678_1484679123.1422222336682
Content-Type: text/plain; charset=UTF-8
> If we did things this way, then for any type you can always explicitly
> request:
>
> - the generic implementation (via "std::no_adl::swap(a, b);"), which
> may not work for all types (just as the current qualified call to swap may
> not work for all types - some types that can't be swapped by the generic
> swap have to "specialize" swap by ADL because they're templates);
> - a custom implementation (assuming it's customized the right way - as
> experts recommend - by defining a swap function in the type's namespace
> rather than specializing std::swap, via "<no 'using std::swap;' or
> 'using std::no_adl::swap;'> swap(a, b);");
> - or you can request the "best" implementation - custom if it exists,
> generic if not - via "std::swap(a, b);".
>
> I have hard time to think of any scenario where someone would actually
want to force a generic implementation, apart from the specialized swap
being broken. But in that case, fix the swap instead of rewriting all code
that would call it.
std types (std::vector, etc.) and classes with customized swap work fine
without any using, that's the exact point of ADL. This tells me that the
natural way to "swap" is to write swap(a,b) without any using. The 'using
std::swap' is required for non-class (fundamental, enum, pointer, member
pointer, array) types and classes without custom swap; this what the
std::adl::swap would help in; but let me show you some alternatives:
1. instead of swap(a,b) write std::bikeshed::swap(a,b);, what has an
implementation of:
template<typename T> auto std::bikeshed::swap(T& x, T& y) { using std::swap;
return swap(x,y); }
std::bikeshed::swap could be also named std::bikeshed_swap, where no using
needed in the implementation due to being already in std namespace. (What
is originally proposed, if I understood right)
2. create a (standard) inline namespace that has nothing else just a using
std::swap;, like this: http://coliru.stacked-crooked.com/a/3625bb457863f7a2
3. there was a proposal for a swap operator, if that is accepted, the whole
problem is obsolete: write a <=> b; instead (or whatever that operator is).
And as you said, for all other standard functions that are supposed to be
specialized like swap (std::begin, std::end, etc.), the same approach shall
be used.
Best, Robert
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_3678_1484679123.1422222336682
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><blockquote class=3D"gmail_quote" style=3D"margin: 0;m=
argin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=
=3D"ltr"><div>If we did things this way, then for any type you can always e=
xplicitly request:<br><ul><li>the generic implementation (via "<span style=
=3D"font-family:courier new,monospace">std::no_adl::swap(a, b);</span>"), w=
hich may not work for all types (just as the current qualified call to swap=
may not work for all types - some types that can't be swapped by the gener=
ic swap have to "specialize" swap by ADL because they're templates);</li><l=
i>a custom implementation (assuming it's customized the right way - as expe=
rts recommend - by defining a swap function in the type's namespace rather =
than specializing std::swap, via "<span style=3D"font-family:courier new,mo=
nospace"><no 'using std::swap;' or 'using std::no_adl::swap;'> swap(a=
, b);</span>");</li><li>or you can request the "best" implementation - cust=
om if it exists, generic if not - via "<span style=3D"font-family:courier n=
ew,monospace">std::swap(a, b);</span>".</li></ul></div></div></blockquote><=
div>I have hard time to think of any scenario where someone would actually =
want to force a generic implementation, apart from the specialized swap bei=
ng broken. But in that case, fix the swap instead of rewriting all code tha=
t would call it.<br><br>std types (std::vector, etc.) and classes with cust=
omized swap work fine without any using, that's the exact point of ADL. Thi=
s tells me that the natural way to "swap" is to write swap(a,b) without any=
using. The 'using std::swap' is required for non-class (fundamental, enum,=
pointer, member pointer, array) types and classes without custom swap; thi=
s what the std::adl::swap would help in; but let me show you some alternati=
ves:<br><br>1. instead of swap(a,b) write <span style=3D"font-family: couri=
er new,monospace;">std::bikeshed::swap(a,b);</span>, what has an implementa=
tion of:<br><div class=3D"prettyprint" style=3D"background-color: rgb(250, =
250, 250); border-color: rgb(187, 187, 187); border-style: solid; border-wi=
dth: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D=
"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-prettify">=
template</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&l=
t;</span><span style=3D"color: #008;" class=3D"styled-by-prettify">typename=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> T</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">></span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"c=
olor: #008;" class=3D"styled-by-prettify">auto</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> std</span><span style=3D"color: #660;"=
class=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">bikeshed</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify">swap</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
>T</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> x</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> T</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">&</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> y</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
</span><span style=3D"color: #008;" class=3D"styled-by-prettify">using</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> std</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">swap</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">return</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> swap</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify">x</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify">y</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">}</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><br></span></div></code></div>std::bikeshed::s=
wap could be also named std::bikeshed_swap, where no using needed in the im=
plementation due to being already in std namespace. (What is originally pro=
posed, if I understood right)<br>2. create a (standard) inline namespace th=
at has nothing else just a <span style=3D"font-family: courier new,monospac=
e;">using std::swap;</span>, like this: http://coliru.stacked-crooked.com/a=
/3625bb457863f7a2<br>3. there was a proposal for a swap operator, if that i=
s accepted, the whole problem is obsolete: write a <=3D> b; instead (=
or whatever that operator is).<br><br>And as you said, for all other standa=
rd functions that are supposed to be specialized like swap (std::begin, std=
::end, etc.), the same approach shall be used.<br><br>Best, Robert<br></div=
></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_3678_1484679123.1422222336682--
------=_Part_3677_3154893.1422222336682--
.