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;
}
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
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.
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:
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
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? :)
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
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).
Yet another work around, is to use '(work)(a)', by enclosing the
function name in parentheses, ADL is inhibited. This looked weird, but
cleaner.
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
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)
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
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
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 :)
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
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....@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