Problem with overloading function templates

H

Hendrik Schober

Hi,

I have a problem, that boils down to the following code:

#include <iostream>
#include <typeinfo>

class Test1 {};
class Test2 {};
class Test3 {};

template< typename T >
struct Cont { T t; };

template< typename T >
class TT { public: TT(T) {} };

struct X {

template< template<typename> class TT, typename T >
static void f(const T& t)
{
std::cout << '\t' << typeid(t).name() << std::endl;
}

template< template<typename> class TT >
static void f(const Test3& t)
{
std::cout << '\t' << typeid(t).name() << std::endl;
}

template< template<typename> class TT, typename T >
static void f(const Cont<T>& c)
{
f<TT>( c.t ); // <== error here
}

};

int main()
{
Cont<Test1> c1;
Cont<Test2> c2;
Cont<Test3> c3;

X::f< TT, Test1 >(c1);
X::f< TT, Test2 >(c2);
X::f< TT, Test3 >(c3);

return 0;
}

For this Comeau and CW9 report (in the line marked
"error here") that the call is ambigous. (VC7.1
accepts the code, BTW.)
First, I don't see what's wrong, but overloading
rules, especially in conjunctions with templates,
are too complicated for me to remember them anyway.
Second, I need a solution. I'm sure I would get it
to work if I would use a class template and partial
specialize it. However, the original code is long
and complex enough without yet another helper class
template...
I would hope that, once the problem is known, a
simpler way could be found. AFAIK, function template
overloading _is_ possible, after all.

TIA,

Schobi

--
(e-mail address removed) is never read
I'm Schobi at suespammers dot org

"Sometimes compilers are so much more reasonable than people."
Scott Meyers
 
L

Leor Zolman

Hi,

I have a problem, that boils down to the following code:

#include <iostream>
#include <typeinfo>

class Test1 {};
class Test2 {};
class Test3 {};

template< typename T >
struct Cont { T t; };

template< typename T >
class TT { public: TT(T) {} };

struct X {

template< template<typename> class TT, typename T >
static void f(const T& t)
{
std::cout << '\t' << typeid(t).name() << std::endl;
}

template< template<typename> class TT >
static void f(const Test3& t)
{
std::cout << '\t' << typeid(t).name() << std::endl;
}

template< template<typename> class TT, typename T >
static void f(const Cont<T>& c)
{
f<TT>( c.t ); // <== error here
}

};

int main()
{
Cont<Test1> c1;
Cont<Test2> c2;
Cont<Test3> c3;

X::f< TT, Test1 >(c1);
X::f< TT, Test2 >(c2);
X::f< TT, Test3 >(c3);

return 0;
}

For this Comeau and CW9 report (in the line marked
"error here") that the call is ambigous. (VC7.1
accepts the code, BTW.)
First, I don't see what's wrong, but overloading
rules, especially in conjunctions with templates,
are too complicated for me to remember them anyway.
Second, I need a solution. I'm sure I would get it
to work if I would use a class template and partial
specialize it. However, the original code is long
and complex enough without yet another helper class
template...
I would hope that, once the problem is known, a
simpler way could be found. AFAIK, function template
overloading _is_ possible, after all.

Perhaps you've OVER-simplified, because it is not clear to my why you have
the template-template parameter there in your templates. I'm not sure, but
if it were used perhaps there might be more of a handle to be had on how to
disambiguate your calls. If you don't really need that
template-template-parameter, then your class can just be this:

struct X {

// template< template<typename> class TT, typename T >
template<typename T >
static void f(const T& t)
{
std::cout << '\t' << typeid(t).name() << std::endl;
}


// template< template<typename> class TT >
static void f(const Test3& t)
{
std::cout << '\t' << typeid(t).name() << std::endl;
}

template< template<typename> class TT, typename T >
static void f(const Cont<T>& c)
{
f( c.t ); // <== error here
}

};

-leor
 
H

Hendrik Schober

Leor Zolman said:
[...]
Perhaps you've OVER-simplified, because it is not clear to my why you have
the template-template parameter there in your templates.

Yes, that's due to the simplification.
In the real code, the template template
arg is used to pick some algorithms that
are to be applied. They are vital to
these functions. :(
I'm not sure, but
if it were used perhaps there might be more of a handle to be had on how to
disambiguate your calls. If you don't really need that
template-template-parameter, then your class can just be this:

struct X {

// template< template<typename> class TT, typename T >
template<typename T >
static void f(const T& t)
{
std::cout << '\t' << typeid(t).name() << std::endl;
}


// template< template<typename> class TT >
static void f(const Test3& t)
{
std::cout << '\t' << typeid(t).name() << std::endl;
}

template< template<typename> class TT, typename T >
static void f(const Cont<T>& c)
{
f( c.t ); // <== error here
}

};

I am surprised. Why would the other template arg
cause the call to be ambiguos?

Schobi

--
(e-mail address removed) is never read
I'm Schobi at suespammers dot org

"Sometimes compilers are so much more reasonable than people."
Scott Meyers
 
L

Leor Zolman

I am surprised. Why would the other template arg
cause the call to be ambiguos?

Because in my simplified version, that second version of f is not a
template.
-leor
 
H

Hendrik Schober

Leor Zolman said:
[...]
Because in my simplified version, that second version of f is not a
template.

-leor

Schobi

--
(e-mail address removed) is never read
I'm Schobi at suespammers dot org

"Sometimes compilers are so much more reasonable than people."
Scott Meyers
 
R

Rob Williscroft

Hendrik Schober wrote in in
comp.lang.c++:
Hi,

I have a problem, that boils down to the following code:

#include <iostream>
#include <typeinfo>

class Test1 {};
class Test2 {};
class Test3 {};

template< typename T >
struct Cont { T t; };

template< typename T >
class TT { public: TT(T) {} };

struct X {

template< template<typename> class TT, typename T >
static void f(const T& t)
{
std::cout << '\t' << typeid(t).name() << std::endl;
}

Here's a Hack-around:

template< template<typename> class TT, typename T >
static void f(const volatile T& tv)
{
T const &t = const_cast< T const & >( tv );
std::cout << '\t' << typeid(t).name() << std::endl;
}
template< template<typename> class TT >
static void f(const Test3& t)
{
std::cout << '\t' << typeid(t).name() << std::endl;
}

template< template<typename> class TT, typename T >
static void f(const Cont<T>& c)
{
f<TT>( c.t ); // <== error here
}

};

int main()
{
Cont<Test1> c1;
Cont<Test2> c2;
Cont<Test3> c3;

X::f< TT, Test1 >(c1);
X::f< TT, Test2 >(c2);
X::f< TT, Test3 >(c3);

return 0;
}

For this Comeau and CW9 report (in the line marked
"error here") that the call is ambigous. (VC7.1
accepts the code, BTW.)

Neither is a better match (they're both exact) and neither is more
specialized, and since there is no such thing as a function partial
specailization, we can't make it so.
First, I don't see what's wrong, but overloading
rules, especially in conjunctions with templates,
are too complicated for me to remember them anyway.
Second, I need a solution. I'm sure I would get it
to work if I would use a class template and partial
specialize it. However, the original code is long
and complex enough without yet another helper class
template...
I would hope that, once the problem is known, a
simpler way could be found. AFAIK, function template
overloading _is_ possible, after all.

I Think Comeau/CW (also g++ 3.2 & 3.4 pre-release) is correct here.
Though I wouldn't bet my shirt on it.

Rob.
 
H

Hendrik Schober

Rob Williscroft said:
[...]
Here's a Hack-around:

template< template<typename> class TT, typename T >
static void f(const volatile T& tv)
{
T const &t = const_cast< T const & >( tv );
std::cout << '\t' << typeid(t).name() << std::endl;
}
Ugh.

[...]

Neither is a better match (they're both exact) and neither is more
specialized,

I always thought a types always is a
better match than a template arg?
Well, I guess I'm wrong...
and since there is no such thing as a function partial
specailization, we can't make it so.


I was afraid I'd have to create a helper
class template.
[...]
Rob.


Thanks,

Schobi

--
(e-mail address removed) is never read
I'm Schobi at suespammers dot org

"Sometimes compilers are so much more reasonable than people."
Scott Meyers
 
H

Hendrik Schober

Hendrik Schober said:

Thanks to everybody who cared. I found this:

template< template<typename> class TT, typename T >
static void f(const T& t, CBool<false> /*isTest3*/)
{
std::cout << '\t' << typeid(t).name() << std::endl;
}

template< template<typename> class TT, typename T >
static void f(const T& t, CBool<true> /*isTest3*/)
{
std::cout << '\t' << typeid(t).name() << std::endl;
}

template< template<typename> class TT, typename T >
static void f(const Cont<T>& c)
{
f<TT>( c.t, CBool<CIsSameType<T,Test3>::result>() );
}

Comeau accepts it, so I assume it's OK...

Schobi

--
(e-mail address removed) is never read
I'm Schobi at suespammers dot org

"Sometimes compilers are so much more reasonable than people."
Scott Meyers
 

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,982
Messages
2,570,189
Members
46,735
Latest member
HikmatRamazanov

Latest Threads

Top