diff options
author | Jeffrey Yasskin <jyasskin@google.com> | 2010-06-15 23:50:08 +0000 |
---|---|---|
committer | Jeffrey Yasskin <jyasskin@google.com> | 2010-06-15 23:50:08 +0000 |
commit | 1390c3d43d0f4eb98be65176cafbf38c1fcbe2b0 (patch) | |
tree | 35c0618bbb2be617d4baf8eafa4aad63c82e17ab /www/cxx_compatibility.html | |
parent | 2a71107b9a0aa647c18e7655c53d9940ab390963 (diff) |
Describe a gcc compatibility problem that occurs when a template calls a
function defined between its declaration and an instantiation, and that
function isn't findable through ADL.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106068 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'www/cxx_compatibility.html')
-rw-r--r-- | www/cxx_compatibility.html | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/www/cxx_compatibility.html b/www/cxx_compatibility.html index 02dabbe8e3..27defc2d8a 100644 --- a/www/cxx_compatibility.html +++ b/www/cxx_compatibility.html @@ -25,6 +25,7 @@ <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> @@ -216,6 +217,129 @@ 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> <!-- ======================================================================= --> |