Namespace goes with template?

X

xman

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;
}
 
V

Victor Bazarov

xman said:
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
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;
}
 
X

xman

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.

xman said:
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;
}
 
X

xman

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.

xman said:
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;
}
 
S

Sylvester Hesp

xman said:
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
 
X

xman

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? :)
 
V

Victor Bazarov

xman said:
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.
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
 
X

xman

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).
 
X

xman

I learned another work around is to use 'work said:
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.
 
S

Sylvester Hesp

xman said:
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
 
X

xman

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)
 
S

Sylvester Hesp

xman said:
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
 
X

xman

[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.
 
S

Sylvester Hesp

xman said:
[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
 
X

xman

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 :)
 
S

Sylvester Hesp

Sylvester Hesp said:
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:

in message
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,117
Latest member
Matilda564
Top