using and ambiguous call

V

valoh

Hi,

is this legal c++ code?

template <typename BaseT> struct A
{
BaseT& this_() { return *static_cast<BaseT*>(this); }

template <typename T> void Foo() { this_().Bar<T>(); }
template <typename T> void Bar() { }
template <typename T> void Bar(i32) { }
};

struct B : public A<B>
{
using A<B>::Bar;

template <typename T> void Bar() { }
};
//..

B test; test.Foo<int>();

when using such a construction I got mixed results on various
compiler. Often I get an ambiguous call to overloaded function error
(A<B>::Bar() vs B::Bar()). Sometime it seem to make a difference when
using template member function or non-template member function.

If it is not legal, why not? Any ideas for good workarounds? I have
template member functions for which i want default implementations and
helpers/wrappers in the base class. Several directly from this base
class derived classes only implementing a subset of the default
implementation. Any ideas?
 
V

Victor Bazarov

is this legal c++ code?

template <typename BaseT> struct A

'BaseT' is a bad name. I would probably call it 'WrappedT'.
{
BaseT& this_() { return *static_cast<BaseT*>(this); }

This can have undefined behaviour if 'BaseT' isn't related to
'A said:
template <typename T> void Foo() { this_().Bar<T>(); }

It seems that you're missing the keyword 'template' here:

... { this_(). template Bar<T>(); }
.. ^^^^^^^^

but I can be wrong.
template <typename T> void Bar() { }
template <typename T> void Bar(i32) { }
};

struct B : public A<B>
{
using A<B>::Bar;

template <typename T> void Bar() { }
};
//..

B test; test.Foo<int>();

when using such a construction I got mixed results on various
compiler. Often I get an ambiguous call to overloaded function error
(A<B>::Bar() vs B::Bar()). Sometime it seem to make a difference when
using template member function or non-template member function.

If it is not legal, why not? Any ideas for good workarounds? I have
template member functions for which i want default implementations and
helpers/wrappers in the base class. Several directly from this base
class derived classes only implementing a subset of the default
implementation. Any ideas?

Try it with all those compilers after adding the keyword 'template',
although I am not sure how it should affect the outcome. It's just
a hunch.

V
 
V

valoh

This can have undefined behaviour if 'BaseT' isn't related to
'A<BaseT>', you realise that of course...

yes, but that's no problem for me. And this design/construction would
be extremely helpful if it would work :-(
template <typename T> void Foo() { this_().Bar<T>(); }

It seems that you're missing the keyword 'template' here:

... { this_(). template Bar<T>(); }
. ^^^^^^^^

but I can be wrong.
[...]

Try it with all those compilers after adding the keyword 'template',
although I am not sure how it should affect the outcome. It's just
a hunch.

doesn't change anything :-(

Any other ideas/workarounds? Any c++ standard gurus who can at least
verify if it should work?
 
J

James Kanze

is this legal c++ code?
template <typename BaseT> struct A
{
BaseT& this_() { return *static_cast<BaseT*>(this); }
template <typename T> void Foo() { this_().Bar<T>(); }

The above line is, I believe, illegal. The call to Bar is in a
dependent context, so Bar can't be looked up until
instantiation. The compiler, however, must know that Bar is a
template in order to correctly parse the code in the template
definition. So the function call should be:
this_().template Bar<T>() ;
But none of my compilers seem to complain, so I'm not sure. I'm
also unable to find where this is discussed in the standard at
the moment. (My understanding is that without the additional
"template", the compilers should interpret the < as "less than",
and not as opening a template argument list. And of course,
template <typename T> void Bar() { }
template <typename T> void Bar(i32) { }

Not sure what i32 is, here. I used "int" when I experimented.
struct B : public A<B>
{
using A<B>::Bar;
template <typename T> void Bar() { }};

B test; test.Foo<int>();
when using such a construction I got mixed results on various
compiler. Often I get an ambiguous call to overloaded function error
(A<B>::Bar() vs B::Bar()). Sometime it seem to make a difference when
using template member function or non-template member function.

Of the compilers I have available, two (g++ and Sun CC) have no
problems with your code, calling B::Bar(), as expected. VC++
seems to have problems with the using declaration, which results
in the ambiguity you mention. (It would seem that the compiler
is including all of the functions Bar from the base class,
rather than just those which aren't hidden.) Drop the using,
however, and it works. This is a bug, but the simple
work-around would be to drop the using, and also define Bar(i32)
in B.
If it is not legal, why not? Any ideas for good workarounds? I have
template member functions for which i want default implementations and
helpers/wrappers in the base class. Several directly from this base
class derived classes only implementing a subset of the default
implementation. Any ideas?

Legal or not, if it doesn't work with the compilers you have to
support, you have to change it. With the compilers I have
access to, the only one which causes a problem is VC++, and
dropping the using seems to solve the problem there. I would
also add the "template" mentionned above, since I suspect that
the code will fail to compile otherwise with some newer
compilers.
 
V

valoh

Of the compilers I have available, two (g++ and Sun CC) have no
problems with your code, calling B::Bar(), as expected. VC++
seems to have problems with the using declaration, which results
in the ambiguity you mention. (It would seem that the compiler
is including all of the functions Bar from the base class,
rather than just those which aren't hidden.) Drop the using,
however, and it works. This is a bug, but the simple
work-around would be to drop the using, and also define Bar(i32)
in B.

Without all the member functions as templates it compiles on vc++,
too. But as vc++ is my main development platform it's really annoying.
The idea was to define default behaviour plus some wrappers in the
base class and only define a subset in several derived classes. When
dropping the using, the wrapper methods will not be resolved so again
copy-paste is needed which I wanted to prevent with this construction
in the first place :)

Thanks for the help. At least I'm now convinced that this would be a
really nice pattern exactly fitting my needs and I have to see how to
convince the vc++ with a least worst workaround :-( well, nothing a
macro can't solve...
 

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

No members online now.

Forum statistics

Threads
473,962
Messages
2,570,134
Members
46,690
Latest member
MacGyver

Latest Threads

Top