|
|
 |
 |
 |
 |
Namespace goes with template?
I defined namespace hpc in main.cpp, so not to clash with other libraries. But I found that, in namespace boo, instantiating a template with a class in namespace hpc, causes compilation errors by clashing the functions in the two namespaces. Is it a compiler bug? or intended C++ behavior? Appreciate if any one can shed some lights for me. See following: func.h: In function 'void boo::rfunc(const boo::R<T>&) [with T = hpc::B]': main.cpp:16: instantiated from here func.h:13: error: call of overloaded 'work(const boo::R<hpc::B>&)' is ambiguous func.h:5: note: candidates are: void boo::work(T) [with T = boo::R<hpc::B>] main.cpp:23: note: void hpc::work(T) [with T = boo::R<hpc::B>] func.h: namespace boo { template <typename T> void work(T n) { std::cout << "good bye work" << std::endl; } template <typename T> class R { }; template <typename T> void rfunc(const R<T>& a) { work(a); } } // namespace boo
main.cpp: #include <iostream> #include "func.h" using std::cout; using std::endl; namespace hpc { class B { }; class A { public: void bfunc(void) { rfunc(n); } protected: boo::R<B> n; };
template <typename T> void work(T n) { cout << "hello world work" << endl; } } // namespace hpc
using hpc::A; int main(int argc, char* argv[]) { A a; a.bfunc(); return 0;
}
xman wrote: > I defined namespace hpc in main.cpp, so not to clash with other > libraries. But I found that, in namespace boo, instantiating a > template with a class in namespace hpc, causes compilation errors by > clashing the functions in the two namespaces. Is it a compiler bug? or > intended C++ behavior?
I believe it's intended. > Appreciate if any one can shed some lights for me. > See following: > func.h: In function 'void boo::rfunc(const boo::R<T>&) [with T = > hpc::B]': > main.cpp:16: instantiated from here > func.h:13: error: call of overloaded 'work(const boo::R<hpc::B>&)' is > ambiguous > func.h:5: note: candidates are: void boo::work(T) [with T = > boo::R<hpc::B>] > main.cpp:23: note: void hpc::work(T) [with T = > boo::R<hpc::B>]
I think you're running into a case of ADL (Argument-Dependent name Lookup). To figure out which function to call, the compiler is allowed to look in the namespaces of arguments (and of template arguments). In your case, since when instantiating 'boo::rfunc<T>', 'R' is from 'boo' and 'T' (deduced as 'hpc::B') is from 'hpc' namespace. Both namespaces are considered making 'work' symbol ambiguous. > func.h: > namespace boo { > template <typename T> > void work(T n) { std::cout << "good bye work" << std::endl; } > template <typename T> class R { }; > template <typename T> > void rfunc(const R<T>& a) { work(a); } > } // namespace boo > main.cpp: > #include <iostream> > #include "func.h"
A side note: here you made inclusion of 'func.h' dependent on the previous inclusion of <iostream>. Better to avoid this. Consider including <iostream> in 'func.h', and still keep it here because this module uses 'cout' and 'endl' as well.
> using std::cout; > using std::endl; > namespace hpc { > class B { }; > class A { > public: > void bfunc(void) { rfunc(n); } > protected: > boo::R<B> n; > }; > template <typename T> > void work(T n) { cout << "hello world work" << endl; } > } // namespace hpc > using hpc::A; > int main(int argc, char* argv[]) > { > A a; > a.bfunc(); > return 0; > }
-- Please remove capital 'A's when replying by e-mail I do not respond to top-posted replies, please don't ask
Hi Victor, Strangely, I tried to use "using boo::work", suppose it should resolve ambiguous name look up, yet it still produces the same error. template <typename T> void rfunc(const R<T>& a) { using boo::work; work(a); }
Thanks for sharing your thoughts. On May 7, 9:31 pm, "Victor Bazarov" <v.Abaza@comAcast.net> wrote:
> xman wrote: > > I defined namespace hpc in main.cpp, so not to clash with other > > libraries. But I found that, in namespace boo, instantiating a > > template with a class in namespace hpc, causes compilation errors by > > clashing the functions in the two namespaces. Is it a compiler bug? or > > intended C++ behavior? > I believe it's intended. > > Appreciate if any one can shed some lights for me. > > See following: > > func.h: In function 'void boo::rfunc(const boo::R<T>&) [with T = > > hpc::B]': > > main.cpp:16: instantiated from here > > func.h:13: error: call of overloaded 'work(const boo::R<hpc::B>&)' is > > ambiguous > > func.h:5: note: candidates are: void boo::work(T) [with T = > > boo::R<hpc::B>] > > main.cpp:23: note: void hpc::work(T) [with T = > > boo::R<hpc::B>] > I think you're running into a case of ADL (Argument-Dependent name > Lookup). To figure out which function to call, the compiler is allowed > to look in the namespaces of arguments (and of template arguments). In > your case, since when instantiating 'boo::rfunc<T>', 'R' is from 'boo' > and 'T' (deduced as 'hpc::B') is from 'hpc' namespace. Both namespaces > are considered making 'work' symbol ambiguous. > > func.h: > > namespace boo { > > template <typename T> > > void work(T n) { std::cout << "good bye work" << std::endl; } > > template <typename T> class R { }; > > template <typename T> > > void rfunc(const R<T>& a) { work(a); } > > } // namespace boo > > main.cpp: > > #include <iostream> > > #include "func.h" > A side note: here you made inclusion of 'func.h' dependent on the > previous inclusion of <iostream>. Better to avoid this. Consider > including <iostream> in 'func.h', and still keep it here because > this module uses 'cout' and 'endl' as well. > > using std::cout; > > using std::endl; > > namespace hpc { > > class B { }; > > class A { > > public: > > void bfunc(void) { rfunc(n); } > > protected: > > boo::R<B> n; > > }; > > template <typename T> > > void work(T n) { cout << "hello world work" << endl; } > > } // namespace hpc > > using hpc::A; > > int main(int argc, char* argv[]) > > { > > A a; > > a.bfunc(); > > return 0; > > } > -- > Please remove capital 'A's when replying by e-mail > I do not respond to top-posted replies, please don't ask
Hi Victor, Strangely, I tried to use "using boo::work", suppose it should resolve ambiguous name look up, yet it still produces the same error. template <typename T> void rfunc(const R<T>& a) { using boo::work; work(a); }
Thanks for sharing your thoughts. On May 7, 9:31 pm, "Victor Bazarov" <v.Abaza@comAcast.net> wrote:
> xman wrote: > > I defined namespace hpc in main.cpp, so not to clash with other > > libraries. But I found that, in namespace boo, instantiating a > > template with a class in namespace hpc, causes compilation errors by > > clashing the functions in the two namespaces. Is it a compiler bug? or > > intended C++ behavior? > I believe it's intended. > > Appreciate if any one can shed some lights for me. > > See following: > > func.h: In function 'void boo::rfunc(const boo::R<T>&) [with T = > > hpc::B]': > > main.cpp:16: instantiated from here > > func.h:13: error: call of overloaded 'work(const boo::R<hpc::B>&)' is > > ambiguous > > func.h:5: note: candidates are: void boo::work(T) [with T = > > boo::R<hpc::B>] > > main.cpp:23: note: void hpc::work(T) [with T = > > boo::R<hpc::B>] > I think you're running into a case of ADL (Argument-Dependent name > Lookup). To figure out which function to call, the compiler is allowed > to look in the namespaces of arguments (and of template arguments). In > your case, since when instantiating 'boo::rfunc<T>', 'R' is from 'boo' > and 'T' (deduced as 'hpc::B') is from 'hpc' namespace. Both namespaces > are considered making 'work' symbol ambiguous. > > func.h: > > namespace boo { > > template <typename T> > > void work(T n) { std::cout << "good bye work" << std::endl; } > > template <typename T> class R { }; > > template <typename T> > > void rfunc(const R<T>& a) { work(a); } > > } // namespace boo > > main.cpp: > > #include <iostream> > > #include "func.h" > A side note: here you made inclusion of 'func.h' dependent on the > previous inclusion of <iostream>. Better to avoid this. Consider > including <iostream> in 'func.h', and still keep it here because > this module uses 'cout' and 'endl' as well. > > using std::cout; > > using std::endl; > > namespace hpc { > > class B { }; > > class A { > > public: > > void bfunc(void) { rfunc(n); } > > protected: > > boo::R<B> n; > > }; > > template <typename T> > > void work(T n) { cout << "hello world work" << endl; } > > } // namespace hpc > > using hpc::A; > > int main(int argc, char* argv[]) > > { > > A a; > > a.bfunc(); > > return 0; > > } > -- > Please remove capital 'A's when replying by e-mail > I do not respond to top-posted replies, please don't ask
"xman" <cshin @gmail.com> wrote in message news:1178548490.792714.3430@u30g2000hsc.googlegroups.com... > Hi Victor, > Strangely, I tried to use "using boo::work", suppose it should resolve > ambiguous name look up, yet it still produces the same error. > template <typename T> > void rfunc(const R<T>& a) { > using boo::work; > work(a); > } > Thanks for sharing your thoughts.
As an administrative note: top-posting is considered to be bad etiquette by some (of not many) of the newsgroup users As for your problem, the using declaration doesn't solve anything. Your merely reintroducing the boo::work function in the current scope, which was already visible. It doesn't hide other visible declarations of work() from the overload resolution (and ADL makes hpc::work() visible, as Victor already explained). If you want to call boo::work, include the namespace name in the function-call: template <typename T> void rfunc(const R<T>& a) { boo::work(a); }
- Sylvester Hesp
> already explained). If you want to call boo::work, include the namespace > name in the function-call: > template <typename T> > void rfunc(const R<T>& a) { > boo::work(a); > }
I understand that boo::work(a) can solve the problem. In my actual codes, boo is actually the boost library namespace, hence, I'm not suppose to modify that part. In this sample code, the boost library in boost namespace may actually clash with my function which I have protected with my own namespace. Can I do something to remove these name clashes? >From the perspective of library code writers, how do I actually
prevent these to happen? e.g. If I am to develop boost library, do I make all template function calls explicit with boost::func()? Isn't that namespace mechanism suppose able to remove name clashes without modifying existing codes extensively? :)
xman wrote: >> already explained). If you want to call boo::work, include the >> namespace name in the function-call: >> template <typename T> >> void rfunc(const R<T>& a) { >> boo::work(a); >> } > I understand that boo::work(a) can solve the problem. In my actual > codes, boo is actually the boost library namespace, hence, I'm not > suppose to modify that part. In this sample code, the boost library in > boost namespace may actually clash with my function which I have > protected with my own namespace. Can I do something to remove these > name clashes?
Yes, easily. Don't name _your_ functions the same as the library ones. >> From the perspective of library code writers, how do I actually > prevent these to happen? e.g. If I am to develop boost library, do I > make all template function calls explicit with boost::func()? Isn't > that namespace mechanism suppose able to remove name clashes without > modifying existing codes extensively? :)
Yes, and it seem that in this particular case Boost folks made a boo (or a boo-boo). If they wanted to make sure that 'boo::work' is called, they ought to write 'boo::' there, as was suggested. V -- Please remove capital 'A's when replying by e-mail I do not respond to top-posted replies, please don't ask
> Yes, easily. Don't name _your_ functions the same as the library ones.
This may not be feasible for example when two sides are indepedent library development, and the person who linked them together is the end user. > Yes, and it seem that in this particular case Boost folks made a boo > (or a boo-boo). If they wanted to make sure that 'boo::work' is called, > they ought to write 'boo::' there, as was suggested.
I learned another work around is to use 'work<R<T> >(a)' so that there isnt need to do ADT. I think this is much better than boo::work(a), because namespace's name can change from time to time (though we should not).
> I learned another work around is to use 'work<R<T> >(a)' so that there > isnt need to do ADT. I think this is much better than boo::work(a), > because namespace's name can change from time to time (though we > should not).
Yet another work around, is to use '(work)(a)', by enclosing the function name in parentheses, ADL is inhibited. This looked weird, but cleaner.
"xman" <cshin @gmail.com> wrote in message news:1178591816.210700.258280@y80g2000hsf.googlegroups.com... > I learned another work around is to use 'work<R<T> >(a)' so that there > isnt need to do ADT.
I suspect you mean ADL? But that doesn't work, both work() functions have the same template signature, no neither one is more specialized than the other. Excplicitely specifying the template parameters won't help you select one overload over the other. Comeau and MSVC++ 2005 still complain about the call being ambiguous. What compiler were you using? Or is your actual code not semantically the same as your example? - Sylvester Hesp
> I suspect you mean ADL? But that doesn't work, both work() functions have > the same template signature, no neither one is more specialized than the > other. Excplicitely specifying the template parameters won't help you select > one overload over the other. Comeau and MSVC++ 2005 still complain about the > call being ambiguous. What compiler were you using? Or is your actual code > not semantically the same as your example?
Right. ADL :) I'm using GCC 4.1.2 on Fedora Core 6, it compiles and run ok. However, Intel Compiler 9.1 fails. Who is wrong? GCC? In this case, may be i should use (work)(a) to be safe. Is (work)(a) work at your compiler? Anyone can try newer VC++ compilers? See below: $ cat main.cpp #include <iostream> #include "func.h" using std::cout; using std::endl; namespace hpc { class B { }; class A { public: void bfunc(void) { rfunc(n); } protected: boo::R<B> n; };
template <typename T> void work(T n) { cout << "hello world work" << endl; } } // namespace hpc
using hpc::A; int main(int argc, char* argv[]) { A a; a.bfunc(); return 0; }
$ cat func.h namespace boo { class current { }; template <typename T> class R { }; template <typename T> void work(T n) { std::cout << "good bye work" << std::endl; }
template <typename T> void rfunc(const R<T>& a) { (work)(a); // ok in gcc 4.1.2. work<R<T> >(a); // doesnt work on intel compiler 9.1, ok in gcc 4.1.2. // work(b); // ?? } } // namespace boo
$ g++ -v Using built-in specs. Target: x86_64-redhat-linux Configured with: ../gcc-4.1.2/configure --prefix=/usr/local --enable- shared --enable-threads=posix --enable-checking=release --enable- __cxa_atexit --with-system-zlib --disable-libunwind-exceptions -- disable-dssi --enable-languages=c,c++,fortran --with-cpu=athlon64 -- host=x86_64-redhat-linux Thread model: posix gcc version 4.1.2 $ g++ main.cpp $ ./a.out good bye work good bye work $ icc -v Version 9.1 $ icc main.cpp func.h(16): error: more than one instance of function template "boo::work" matches the argument list: function template "void boo::work(T)" function template "void hpc::work(T)" argument types are: (const boo::R<hpc::B>) work<R<T> >(a); // doesnt work on intel compiler 9.1, ok in gcc 4.1.2. ^ detected during instantiation of "void boo::rfunc(const boo::R<T> &) [with T=hpc::B]" compilation aborted for main.cpp (code 2)
"xman" <cshin @gmail.com> wrote in message news:1178622125.475127.147540@h2g2000hsg.googlegroups.com... >> I suspect you mean ADL? But that doesn't work, both work() functions have >> the same template signature, no neither one is more specialized than the >> other. Excplicitely specifying the template parameters won't help you >> select >> one overload over the other. Comeau and MSVC++ 2005 still complain about >> the >> call being ambiguous. What compiler were you using? Or is your actual >> code >> not semantically the same as your example? > Right. ADL :) I'm using GCC 4.1.2 on Fedora Core 6, it compiles and > run ok. However, Intel Compiler 9.1 fails. Who is wrong? GCC? In this > case, may be i should use (work)(a) to be safe. Is (work)(a) work at > your compiler? Anyone can try newer VC++ compilers?
Gcc is definitely wrong. But it's interesting... (work)(a) works on both Comeau and VC++ 2005. However, after reading the standard on this, I must say I'm confused about whether it *should* work. [ADL] 3.4.2/1 When an unqualified name is used as the postfix-expression in a function call (5.2.2), other namespaces not considered during the usual unqualified lookup (3.4.1) may be searched [...] [Function call] 5.2.2/1 There are two kinds of function call: ordinary function call and member function call. A function call is a postfix expression followed by parentheses containing a possibly empty, comma-separated list of expressions which constitute the arguments to the function. For an ordinary function call, the postfix expression shall be either an lvalue that refers to a function (in which case the function-to-pointer standard conversion (4.3) is suppressed on the postfix expression), or it shall have pointer to function type. [Overload resolution] 13.3.1.1/1 Recall from 5.2.2, that a function call is a postfix-expression, possibly nested arbitrarily deep in parentheses, followed by an optional expression-list enclosed in parentheses: ( ... (opt postfix-expression ) ... )opt ( expression-listopt ) Overload resolution is required if the postfix-expression is the name of a function, a function template (14.5.5), an object of class type, or a set of pointers-to-function. 13.3.1.1/1 specifically denotes the nested parantheses that may surround the postfix-expression, whereas 5.2.2/1 simply refers to a postfix-expression. While 13.3.1.1/1 is not important here (overload resolution is applied *after* name lookup, and the name lookup is causing the ambiguity here), I do find it disturbing that they refer back to 5.2.2 as if the parantheses were mentioned there as well, so I'm not quite sure whether the omission of the parantheses in 5.2.2 was intentional. - Sylvester Hesp
> [ADL] > 3.4.2/1 When an unqualified name is used as the postfix-expression in a > function call (5.2.2), other namespaces not considered > during the usual unqualified lookup (3.4.1) may be searched [...]
It's not a must to search other namespaces. Since I already specify R<T>, and class R is only defined in the current namespace, naturally, we do not need to search other namespaces, since we cant find R<T> in other namespaces.
"xman" <cshin @gmail.com> wrote in message news:1178645393.586007.135640@n59g2000hsh.googlegroups.com... >> [ADL] >> 3.4.2/1 When an unqualified name is used as the postfix-expression in a >> function call (5.2.2), other namespaces not considered >> during the usual unqualified lookup (3.4.1) may be searched [...] > It's not a must to search other namespaces. Since I already specify > R<T>, and class R is only defined in the current namespace, naturally, > we do not need to search other namespaces, since we cant find R<T> in > other namespaces.
You're mistaken. The point is namespaces are searched based on the function arguments. By explicitely specifying the template arguments you still not avoid passing that one argument of type R<T>, and so both namespaces of R *and* T are searched. This holds even if you explicitely called work<foo<bar> >(n) where n is of type R<T>. Note, btw, that this kind of ADL is under heavy fire in the C++ working group. There are a bunch of proposals out there that will make your original code compile flawlessly (it would find boo::work without ambiguity) under C++09 (if the proposals make it in that is) - Sylvester Hesp
> You're mistaken. The point is namespaces are searched based on the function > arguments. By explicitely specifying the template arguments you still not > avoid passing that one argument of type R<T>, and so both namespaces of R > *and* T are searched. This holds even if you explicitely called > work<foo<bar> >(n) where n is of type R<T>.
Got it. I was previously confused with when choosing a template, it'll select the more specialized one. > Note, btw, that this kind of ADL is under heavy fire in the C++ working > group. There are a bunch of proposals out there that will make your original > code compile flawlessly (it would find boo::work without ambiguity) under > C++09 (if the proposals make it in that is)
I hope these proposals do not create other surprises to me :)
"xman" <cshin @gmail.com> wrote in message news:1178714593.686072.49930@q75g2000hsh.googlegroups.com... >> Note, btw, that this kind of ADL is under heavy fire in the C++ working >> group. There are a bunch of proposals out there that will make your >> original >> code compile flawlessly (it would find boo::work without ambiguity) under >> C++09 (if the proposals make it in that is) > I hope these proposals do not create other surprises to me :)
You can read it for yourself if you're interested :) http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2103.pdf These about so called explicit namespaces might also be an interesting read http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1408.html http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1691.html
"Sylvester Hesp" <s.h @oisyn.nl> wrote in message news:46408693$0$328$e4fe514c@news.xs4all.nl... > "xman" <cshin @gmail.com> wrote in message > news:1178622125.475127.147540@h2g2000hsg.googlegroups.com... >> Right. ADL :) I'm using GCC 4.1.2 on Fedora Core 6, it compiles and >> run ok. However, Intel Compiler 9.1 fails. Who is wrong? GCC? In this >> case, may be i should use (work)(a) to be safe. Is (work)(a) work at >> your compiler? Anyone can try newer VC++ compilers? > Gcc is definitely wrong. > But it's interesting... (work)(a) works on both Comeau and VC++ 2005. > However, after reading the standard on this, I must say I'm confused about > whether it *should* work.
Yes, it should. Alberto Ganesh Barbati provided me with a clear explanation in comp.std.c++ of why ADL is not applied when putting the function names in parantheses: "Alberto Ganesh Barbati" wrote in message
news:5vr0i.3297$U01.49313@twister1.libero.it... > The key point is in paragraph 3.4.2/1 above. It says (with added > emphasis): "When an unqualified name is used *as* the postfix-expression > in a function call [...]". Notice that here we are definitely referring > to the definition form A! So if I write: > (foo)(n); > the postfix-expression 3.4.2/1 is referring to is "(foo)". As "(foo)" is > *not* an unqualified name, ADL doesn't apply. The fact the "(foo)" > contains, nested in parentheses, an unqualified name is irrelevant.
So using parantheses would definitely be the way to go :). - Sylvester
|
 |
 |
 |
 |
|