diff options
author | John McCall <rjmccall@apple.com> | 2010-03-17 07:10:56 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-03-17 07:10:56 +0000 |
commit | 489722fb5c2f8b6642c1665b33d8751b752cc83c (patch) | |
tree | b4d61f4bafa32280ba1f889dcf9ac110f04ac06c | |
parent | 6243e335f48ad86b79cfc172586445a458f77c36 (diff) |
Add another compatibility note and tweak a few of the existing ones.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98717 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | www/cxx_compatibility.html | 98 |
1 files changed, 61 insertions, 37 deletions
diff --git a/www/cxx_compatibility.html b/www/cxx_compatibility.html index 9bf9865687..e5fd63ef9c 100644 --- a/www/cxx_compatibility.html +++ b/www/cxx_compatibility.html @@ -23,7 +23,8 @@ <li><a href="#intro">Introduction</a></li> <li><a href="#vla">Variable-length arrays</a></li> <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">Dependent name lookup into dependent bases of class templates</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="#default_init_const">Default initialization of const variable of a class type requires user-defined default constructor</a></li> </ul> @@ -97,87 +98,110 @@ class SomeClass { const double SomeClass::SomeConstant<b> = 0.5</b>; </pre> +Note that the forthcoming C++0x standard will allow this. + <!-- ======================================================================= --> -<h2 id="dep_lookup">Dependent name lookup into dependent bases of class templates</h2> +<h2 id="dep_lookup">Unqualified lookup in templates</h2> <!-- ======================================================================= --> Some versions of GCC accept the following invalid code: <pre> -template <typename T> -class Base { - public: - void DoThis(T x) {} +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 +</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>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. + +<!-- ======================================================================= --> +<h2 id="dep_lookup_bases">Unqualified lookup into dependent bases of class templates</h2> +<!-- ======================================================================= --> + +Some versions of GCC accept the following invalid code: + +<pre> +template <typename T> struct Base { + void DoThis(T x) {} static void DoThat(T x) {} }; -template <typename T> -class Derived : public Base<T> { - public: +template <typename T> struct Derived : public Base<T> { void Work(T x) { DoThis(x); // Invalid! DoThat(x); // Invalid! } }; - -void Test() { - Derived<int> d; - d.Work(42); -} </pre> -Clang correctly rejects it with the following errors: +Clang correctly rejects it with the following errors +(when <tt>Derived</tt> is eventually instantiated): <pre> -my_file.cpp:13:5: error: use of undeclared identifier 'DoThis' +my_file.cpp:8:5: error: use of undeclared identifier 'DoThis' DoThis(x); ^ this-> -my_file.cpp:20:5: note: in instantiation of member function 'Derived<int>::Work' requested here - d.Work(42); - ^ -my_file.cpp:4:8: note: must qualify identifier to find this declaration in dependent base class +my_file.cpp:2:8: note: must qualify identifier to find this declaration in dependent base class void DoThis(T x) {} ^ -my_file.cpp:14:5: error: use of undeclared identifier 'DoThat' +my_file.cpp:9:5: error: use of undeclared identifier 'DoThat' DoThat(x); ^ this-> -my_file.cpp:6:15: note: must qualify identifier to find this declaration in dependent base class +my_file.cpp:3:15: note: must qualify identifier to find this declaration in dependent base class static void DoThat(T x) {} </pre> -The reason the code is invalid is that in -class <tt>Derived<T></tt>, the base class type <tt>Base<T></tt> -depends on the template argument <tt>T</tt> (hence it's called a dependent base -class in C++ jargon), and C++ doesn't look at the members of a -dependent base class when resolving unqualified calls like <tt>DoThis(x)</tt> -and <tt>DoThat(x)</tt> (see [temp.dep] p3 for details). The fix, as Clang tells -you, is to prefix the calls with <tt>this-></tt>: +Like we said <a href="#dep_lookup">above</a>, unqualified names like +<tt>DoThis</tt> and <tt>DoThat</tt> are looked up when the template +<tt>Derived</tt> is defined, not when it's instantiated. When we look +up a name used in a class, we usually look into the base classes. +However, we can't look into the base class <tt>Base<T></tt> +because its type depends on the template argument <tt>T</tt>, so the +standard says we should just ignore it. See [temp.dep]p3 for details. + +<p>The fix, as Clang tells you, is to tell the compiler that we want a +class member by prefixing the calls with <tt>this-></tt>: <pre> -... -template <typename T> -class Derived : public Base<T> { - public: void Work(T x) { <b>this-></b>DoThis(x); <b>this-></b>DoThat(x); } -}; -... </pre> -Alternatively, since DoThat() is a static method, you can also write +Alternatively, you can tell the compiler exactly where to look: <pre> void Work(T x) { - <b>this-></b>DoThis(x); + <b>Base<T></b>::DoThis(x); <b>Base<T></b>::DoThat(x); } </pre> +This works whether the methods are static or not, but be careful: +if <tt>DoThis</tt> is virtual, calling it this way will bypass virtual +dispatch! + <!-- ======================================================================= --> <h2 id="default_init_const">Default initialization of const variable of a class type requires user-defined default constructor</h2> <!-- ======================================================================= --> |