diff options
author | Jeffrey Yasskin <jyasskin@google.com> | 2010-06-16 01:12:12 +0000 |
---|---|---|
committer | Jeffrey Yasskin <jyasskin@google.com> | 2010-06-16 01:12:12 +0000 |
commit | f44ea727c0f632f9b6a262cf36dd5c9323c2467f (patch) | |
tree | 1912c6b0087a24129a2bf0c2e5cc4bb3fa5e5d86 | |
parent | 9d3347a5887d2d25afe8b0bd35783a72ec86cce2 (diff) |
Fix template ordering compatibility docs. I missed another section that covered
the same thing.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106076 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | www/cxx_compatibility.html | 234 |
1 files changed, 90 insertions, 144 deletions
diff --git a/www/cxx_compatibility.html b/www/cxx_compatibility.html index 27defc2d8a..46e3a9f909 100644 --- a/www/cxx_compatibility.html +++ b/www/cxx_compatibility.html @@ -25,7 +25,6 @@ <li><a href="#init_static_const">Initialization of non-integral static const data members within a class definition</a></li> <li><a href="#dep_lookup">Unqualified lookup in templates</a></li> <li><a href="#dep_lookup_bases">Unqualified lookup into dependent bases of class templates</a></li> -<li><a href="#declaration_ordering">Template uses of a function must either find the function by ADL or come after the declaration of the function</a></li> <li><a href="#undep_incomplete">Incomplete types in templates</a></li> <li><a href="#bad_templates">Templates with no valid instantiations</a></li> <li><a href="#default_init_const">Default initialization of const variable of a class type requires user-defined default constructor</a></li> @@ -118,33 +117,103 @@ Note that the forthcoming C++0x standard will allow this. <h2 id="dep_lookup">Unqualified lookup in templates</h2> <!-- ======================================================================= --> -Some versions of GCC accept the following invalid code: +<p>Some versions of GCC accept the following invalid code: <pre> -template <typename T> struct Foo { - void Work(T x) { - func(x); - } -}; -... -void func(int x); -... -template struct Foo<int>; // or anything else that instantiates Foo<int>::Work +#include <iostream> +#include <utility> + +template<typename T> +void Dump(const T& value) { + std::cout << value << "\n"; +} + +namespace ns { + struct Data {}; +} + +std::ostream& operator<<(std::ostream& out, ns::Data) { + return out << "Some data"; +} + +void Use() { + Dump(std::make_pair(3, 4.5)); + Dump(ns::Data()); +} + +template<typename T, typename U> +std::ostream& operator<<(std::ostream& out, const std::pair<T, U>& p) { + return out << '(' << p.first << ", " << p.second << ")"; +} </pre> -The standard says that unqualified names like <tt>func</tt> are looked up -when the template is defined, not when it's instantiated. Since -<tt>void func(int)</tt> was not declared yet when <tt>Foo</tt> was -defined, it's not considered. The fix is usually to -declare <tt>func</tt> before <tt>Foo</tt>. +<p>Clang complains:</p> + +<pre> +<b>test.cc:6:13: <span class=error>error:</span> invalid operands to binary expression ('ostream' (aka 'basic_ostream<char>') and 'std::pair<int, double> const')</b> + std::cout << value << "\n"; + <span class=caret>~~~~~~~~~ ^ ~~~~~</span> +<b>test.cc:18:3: note:</b> in instantiation of function template specialization 'Dump<std::pair<int, double> >' requested here + 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<char>') and 'ns::Data const')</b> + std::cout << value << "\n"; + <span class=caret>~~~~~~~~~ ^ ~~~~~</span> +<b>test.cc:19:3: note:</b> in instantiation of function template specialization 'Dump<ns::Data>' requested here + Dump(ns::Data()); + <span class=caret>^</span> +2 errors generated. +</pre> + +<p>The standard, in [temp.dep.candidate], says that unqualified names +like <tt>operator<<</tt> are looked up when the template is +defined, not when it's instantiated. Since +<tt>operator<<(std::ostream&, const std::pair<>&)</tt> +and <tt>operator<<(std::ostream&, ns::Data)</tt> were not +declared yet when <tt>Dump</tt> was defined, they're not considered. <p>This is complicated by <i>argument-dependent lookup</i> (ADL), which is done when unqualified names are called as functions, -like <tt>func(x)</tt> above. The standard says that ADL is performed -in both places if any of the arguments are type-dependent, like -<tt>x</tt> is in this example. However, ADL does nothing for builtin -types like <tt>int</tt>, so the example is still invalid. See -[basic.lookup.argdep] for more information. +like <tt>operator<<</tt> above. The standard says that ADL is +performed in both places if any of the arguments are type-dependent, +like <tt>value</tt> and <tt>p</tt> are in this example. + +<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 +so that ADL applies. (Note that it still needs to be declared before +the template is <i>instantiated</i>, and that ADL doesn't apply to +built-in types.) +</ol> + +<pre> +#include <iostream> +#include <utility> + +template<typename T, typename U> // Fix 2 +std::ostream& operator<<(std::ostream& out, const std::pair<T, U>& p) { + return out << '(' << p.first << ", " << p.second << ")"; +} + +template<typename T> +void Dump(const T& value) { + std::cout << value << "\n"; +} + +namespace ns { + struct Data {}; + + std::ostream& operator<<(std::ostream& out, Data) { // Fix 3 + return out << "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> @@ -217,129 +286,6 @@ if <tt>DoThis</tt> is virtual, calling it this way will bypass virtual dispatch! <!-- ======================================================================= --> -<h2 id="declaration_ordering">Template uses of a function must either find the function by ADL or come after the declaration of the function</h2> -<!-- ======================================================================= --> - -<p>For example, gcc-4.4 accepts the following code:</p> - -<pre> -#include <iostream> -#include <utility> -#include <vector> - -template<typename T> -void Dump(const T& value) { - std::cout << value << "\n"; -} - -template<typename T, typename U> -std::ostream& operator<<(std::ostream& out, const std::pair<T, U>& i) { - return out << '(' << i.first << ", " << i.second << ")"; -} - -namespace ns { - struct Data {}; -} - -std::ostream& operator<<(std::ostream& out, ns::Data) { - return out << "Some data"; -} - -void Use() { - Dump(std::make_pair(3, 4.5)); - Dump(ns::Data()); - Dump(std::vector<const char*>(1, "Hello World")); -} - -template<typename T> -std::ostream& operator<<(std::ostream& out, const std::vector<T>& vec) { - out << '['; - for (size_t i = 0, size = vec.size(); i != size; ++i) { - if (i != 0) - out << ", "; - out << vec[i]; - } - return out << ']'; -} -</pre> - -<p>while clang, following the rules in <tt>[temp.dep.candidate]</tt> -complains:</p> - -<pre> -<b>test.cc:7:13: <span class=error>error:</span> invalid operands to binary expression ('ostream' (aka 'basic_ostream<char>') and 'std::pair<int, double> const')</b> - std::cout << value << "\n"; - <span class=caret>~~~~~~~~~ ^ ~~~~~</span> -<b>test.cc:24:3: note:</b> in instantiation of function template specialization 'Dump<std::pair<int, double> >' requested here - Dump(std::make_pair(3, 4.5)); - <span class=caret>^</span> -<b>test.cc:7:13: <span class=error>error:</span> invalid operands to binary expression ('ostream' (aka 'basic_ostream<char>') and 'ns::Data const')</b> - std::cout << value << "\n"; - <span class=caret>~~~~~~~~~ ^ ~~~~~</span> -<b>test.cc:25:3: note:</b> in instantiation of function template specialization 'Dump<ns::Data>' requested here - Dump(ns::Data()); - <span class=caret>^</span> -<b>test.cc:7:13: <span class=error>error:</span> invalid operands to binary expression ('ostream' (aka 'basic_ostream<char>') and 'std::vector<char const *, std::allocator<char const *> > const')</b> - std::cout << value << "\n"; - <span class=caret>~~~~~~~~~ ^ ~~~~~</span> -<b>test.cc:26:3: note:</b> in instantiation of function template specialization 'Dump<std::vector<char const *, std::allocator<char const *> > >' requested here - Dump(std::vector<const char*>(1, "Hello World")); - <span class=caret>^</span> -3 errors generated. -</pre> - -<p>The fix is to</p> -<ol><li>Add a declaration before the use of the function, or -<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. (Note that it still needs to be declared before the -template is <i>instantiated</i>.) -</ol> - -<pre> -#include <iostream> -#include <utility> -#include <vector> - -template<typename T> // Fix 1. -std::ostream& operator<<(std::ostream& out, const std::vector<T>& vec); - -template<typename T, typename U> // Fix 2. -std::ostream& operator<<(std::ostream& out, const std::pair<T, U>& i) { - return out << '(' << i.first << ", " << i.second << ")"; -} - -template<typename T> -void Dump(const T& value) { - std::cout << value << "\n"; -} - -namespace ns { - struct Data {}; - std::ostream& operator<<(std::ostream& out, Data) { // Fix 3. - return out << "Some data"; - } -} - -void Use() { - Dump(std::make_pair(3, 4.5)); - Dump(ns::Data()); - Dump(std::vector<const char*>(1, "Hello World")); -} - -template<typename T> -std::ostream& operator<<(std::ostream& out, const std::vector<T>& vec) { - out << '['; - for (size_t i = 0, size = vec.size(); i != size; ++i) { - if (i != 0) - out << ", "; - out << vec[i]; - } - return out << ']'; -} -</pre> - -<!-- ======================================================================= --> <h2 id="undep_incomplete">Incomplete types in templates</h2> <!-- ======================================================================= --> |