Rework the unqualified-lookup-in-templates section of the compatibility

document.  jyasskin, let me know if this meets your needs.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106098 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
John McCall 2010-06-16 10:48:16 +00:00
Родитель 52a02758fb
Коммит 50163009b1
1 изменённых файлов: 83 добавлений и 69 удалений

Просмотреть файл

@ -120,8 +120,60 @@ Note that the forthcoming C++0x standard will allow this.
<p>Some versions of GCC accept the following invalid code: <p>Some versions of GCC accept the following invalid code:
<pre> <pre>
#include &lt;iostream&gt; template &lt;typename T&gt; T Squared(T x) {
#include &lt;utility&gt; return Multiply(x, x);
}
int Multiply(int x, int y) {
return x * y;
}
int main() {
Squared(5);
}
</pre>
<p>Clang complains:
<pre> <b>my_file.cpp:2:10: <span class="error">error:</span> use of undeclared identifier 'Multiply'</b>
return Multiply(x, x);
<span class="caret"> ^</span>
<b>my_file.cpp:10:3: <span class="note">note:</span> in instantiation of function template specialization 'Squared&lt;int&gt;' requested here</b>
Squared(5);
<span class="caret"> ^</span>
</pre>
<p>The C++ standard says that unqualified names like <q>Multiply</q>
are looked up in two ways.
<p>First, the compiler does <i>unqualified lookup</i> in the scope
where the name was written. For a template, this means the lookup is
done at the point where the template is defined, not where it's
instantiated. Since <tt>Multiply</tt> hasn't been declared yet at
this point, unqualified lookup won't find it.
<p>Second, if the name is called like a function, then the compiler
also does <i>argument-dependent lookup</i> (ADL). (Sometimes
unqualified lookup can suppress ADL; see [basic.lookup.argdep]p3 for
more information.) In ADL, the compiler looks at the types of all the
arguments to the call. When it finds a class type, it looks up the
name in that class's namespace; the result is all the declarations it
finds in those namespaces, plus the declarations from unqualified
lookup. However, the compiler doesn't do ADL until it knows all the
argument types.
<p>In our example, <tt>Multiply</tt> is called with dependent
arguments, so ADL isn't done until the template is instantiated. At
that point, the arguments both have type <tt>int</tt>, which doesn't
contain any class types, and so ADL doesn't look in any namespaces.
Since neither form of lookup found the declaration
of <tt>Multiply</tt>, the code doesn't compile.
<p>Here's another example, this time using overloaded operators,
which obey very similar rules.
<pre>#include &lt;iostream&gt;
template&lt;typename T&gt; template&lt;typename T&gt;
void Dump(const T&amp; value) { void Dump(const T&amp; value) {
@ -132,88 +184,50 @@ namespace ns {
struct Data {}; struct Data {};
} }
std::ostream& operator&lt;&lt;(std::ostream&amp; out, ns::Data) { std::ostream&amp; operator&lt;&lt;(std::ostream&amp; out, ns::Data data) {
return out &lt;&lt; "Some data"; return out &lt;&lt; "Some data";
} }
void Use() { void Use() {
Dump(std::make_pair(3, 4.5));
Dump(ns::Data()); Dump(ns::Data());
} }</pre>
template&lt;typename T, typename U&gt; <p>Again, Clang complains about not finding a matching function:</p>
std::ostream&amp; operator&lt;&lt;(std::ostream& out, const std::pair&lt;T, U&gt;&amp; p) {
return out &lt;&lt; '(' &lt;&lt; p.first &lt;&lt; ", " &lt;&lt; p.second &lt;&lt; ")";
}
</pre>
<p>Clang complains:</p>
<pre> <pre>
<b>test.cc:6:13: <span class=error>error:</span> invalid operands to binary expression ('ostream' (aka 'basic_ostream&lt;char&gt;') and 'std::pair&lt;int, double&gt; const')</b> <b>my_file.cpp:5:13: <span class="error">error:</span> invalid operands to binary expression ('ostream' (aka 'basic_ostream&lt;char&gt;') and 'ns::Data const')</b>
std::cout &lt;&lt; value &lt;&lt; "\n"; std::cout &lt;&lt; value &lt;&lt; "\n";
<span class=caret>~~~~~~~~~ ^ ~~~~~</span> <span class="caret">~~~~~~~~~ ^ ~~~~~</span>
<b>test.cc:18:3: note:</b> in instantiation of function template specialization 'Dump&lt;std::pair&lt;int, double&gt; &gt;' requested here <b>my_file.cpp:17:3: <span class="note">note:</span> in instantiation of function template specialization 'Dump&lt;ns::Data&gt;' requested here</b>
Dump(std::make_pair(3, 4.5));
<span class=caret>^</span>
<b>test.cc:6:13: <span class=error>error:</span> invalid operands to binary expression ('ostream' (aka 'basic_ostream&lt;char&gt;') and 'ns::Data const')</b>
std::cout &lt;&lt; value &lt;&lt; "\n";
<span class=caret>~~~~~~~~~ ^ ~~~~~</span>
<b>test.cc:19:3: note:</b> in instantiation of function template specialization 'Dump&lt;ns::Data&gt;' requested here
Dump(ns::Data()); Dump(ns::Data());
<span class=caret>^</span> <span class="caret">^</span>
2 errors generated.
</pre> </pre>
<p>The standard, in [temp.dep.candidate], says that unqualified names <p>Just like before, unqualified lookup didn't find any declarations
like <tt>operator&lt;&lt;</tt> are looked up when the template is with the name <tt>operator&lt;&lt;</tt>. Unlike before, the argument
defined, not when it's instantiated. Since types both contain class types: one of them is an instance of the
<tt>operator&lt;&lt;(std::ostream&amp;, const std::pair&lt;>&amp;)</tt> class template type <tt>std::basic_ostream</tt>, and the other is the
and <tt>operator&lt;&lt;(std::ostream&amp;, ns::Data)</tt> were not type <tt>ns::Data</tt> that we declared above. Therefore, ADL will
declared yet when <tt>Dump</tt> was defined, they're not considered. look in the namespaces <tt>std</tt> and <tt>ns</tt> for
an <tt>operator&lt;&lt;</tt>. Since one of the argument types was
still dependent during the template definition, ADL isn't done until
the template is instantiated during <tt>Use</tt>, which means that
the <tt>operator&lt;&lt;</tt> we want it to find has already been
declared. Unfortunately, it was declared in the global namespace, not
in either of the namespaces that ADL will look in!
<p>This is complicated by <i>argument-dependent lookup</i> (ADL), <p>There are two ways to fix this problem:</p>
which is done when unqualified names are called as functions, <ol><li>Make sure the function you want to call is declared before the
like <tt>operator&lt;&lt;</tt> above. The standard says that ADL is template that might call it. This is the only option if none of its
performed in both places if any of the arguments are type-dependent, argument types contain classes. You can do this either by moving the
like <tt>value</tt> and <tt>p</tt> are in this example. template definition, or by moving the function definition, or by
adding a forward declaration of the function before the template.</li>
<p>The fix is usually to</p>
<ol><li>Add a declaration before the use of the function,
<li>Move the definition to before the use of the function, or
<li>Move the function into the same namespace as one of its arguments <li>Move the function into the same namespace as one of its arguments
so that ADL applies. (Note that it still needs to be declared before so that ADL applies.</li></ol>
the template is <i>instantiated</i>, and that ADL doesn't apply to
built-in types.)
</ol>
<pre> <p>For more information about argument-dependent lookup, see
#include &lt;iostream> [basic.lookup.argdep]. For more information about the ordering of
#include &lt;utility> lookup in templates, see [temp.dep.candidate].
template&lt;typename T, typename U> // Fix 2
std::ostream& operator&lt;&lt;(std::ostream& out, const std::pair&lt;T, U>& p) {
return out &lt;&lt; '(' &lt;&lt; p.first &lt;&lt; ", " &lt;&lt; p.second &lt;&lt; ")";
}
template&lt;typename T>
void Dump(const T& value) {
std::cout &lt;&lt; value &lt;&lt; "\n";
}
namespace ns {
struct Data {};
std::ostream& operator&lt;&lt;(std::ostream& out, Data) { // Fix 3
return out &lt;&lt; "Some data";
}
}
void Use() {
Dump(std::make_pair(3, 4.5));
Dump(ns::Data());
}
</pre>
<!-- ======================================================================= --> <!-- ======================================================================= -->
<h2 id="dep_lookup_bases">Unqualified lookup into dependent bases of class templates</h2> <h2 id="dep_lookup_bases">Unqualified lookup into dependent bases of class templates</h2>