automatic conversion of template arguments?

B

bartek

Please consider the following scenario below (sketch of).
There are two templates defined: A and B, both with mutual conversion
operators defined.
Also, there's a free function template 'do_something' with the following
signature:

template <class T>
inline void do_something(B<T> const& arg);

Now, given an object of type, say, A<int> passed as a parameter to that
function, the compiler gives up when deducing template arguments. Is it
possible to somehow go around this, without using explicit template
specification? It's a show-stopper for templated operators.

One possible solution I can think of is, of course, to derive both A and
B from some common base class, and use the 'curious base' pattern...
I'd like to keep it simple, though...

See below for the whole picture.

//-------------------------------------------------------------------
// forward declarations
template <class T> class A;
template <class T> class B;

//-------------------------------------------------------------------

template <class T>
class A {
T member;
public:
A(T const& from) : member(from) { }
operator B<T>() const { return member; }
};

//-------------------------------------------------------------------

template <class T>
class B {
T member;
public:
B(T const& from) : member(from) { }
operator A<T>() const { return member; }
};

//-------------------------------------------------------------------

template <class T>
inline void do_something(B<T> const& arg) {
// do something
}

//-------------------------------------------------------------------

int main() {
A<int> a(5);
do_something(a); // ERROR - could not deduce template argument.
do_something<int>(a); // OK
return 0;
}
 
S

Siemel Naran

bartek said:
template <class T>
class A {
T member;
public:
A(T const& from) : member(from) { }
operator B<T>() const { return member; }
};

//-------------------------------------------------------------------

template <class T>
class B {
T member;
public:
B(T const& from) : member(from) { }
operator A<T>() const { return member; }
};

//-------------------------------------------------------------------

template <class T>
inline void do_something(B<T> const& arg) {
// do something
}

//-------------------------------------------------------------------

int main() {
A<int> a(5);
do_something(a); // ERROR - could not deduce template argument.
do_something<int>(a); // OK
return 0;
}

My compiler Borland C++ Builder 6 gives the error too

[C++ Error] Unit1.cpp(34): E2285 Could not find a match for
'do_something<T>(A<int>)'

The second do_something<int> works.

Don't know the reasons.

See if you really need operator conversions. If it's just nice to have and
leads to a nice syntax, maybe you can do without it. People using operator
conversions say it often results in unwanted conversions, unwanted error
messages, etc, so best bet is to avoid them as much as possible. But use
them as always for proxy objects.
 
R

Rob Williscroft

bartek wrote in in
comp.lang.c++:
Please consider the following scenario below (sketch of).
There are two templates defined: A and B, both with mutual conversion
operators defined.
Also, there's a free function template 'do_something' with the following
signature:

template <class T>
inline void do_something(B<T> const& arg);

Now, given an object of type, say, A<int> passed as a parameter to that
function, the compiler gives up when deducing template arguments. Is it
possible to somehow go around this, without using explicit template
specification? It's a show-stopper for templated operators.

The compiler can't deduce that a B<T> is called for when given an
A said:
One possible solution I can think of is, of course, to derive both A and
B from some common base class, and use the 'curious base' pattern...
I'd like to keep it simple, though...

There's a whole bunch of tricks you can use, I wouldn't describe
any of them as simple though.

This is about the most straight forward though:

template < typename T >
struct arg_from_template;

template < typename T, template <typename> class C >
struct arg_from_template< C< T > >
{
typedef T type;
};

template < typename T >
void do_something( T const &arg )
{
typedef typename arg_from_template< T >::type real_T;
typedef B< real_T > b_type;

b_type const &real_arg = arg;

// Do whatever with real_arg ...
}

Rob.
 
D

Denis Remezov

bartek said:
Please consider the following scenario below (sketch of).
There are two templates defined: A and B, both with mutual conversion
operators defined.
Also, there's a free function template 'do_something' with the following
signature:

template <class T>
inline void do_something(B<T> const& arg);

Now, given an object of type, say, A<int> passed as a parameter to that
function, the compiler gives up when deducing template arguments. Is it
possible to somehow go around this, without using explicit template
specification? It's a show-stopper for templated operators.
[snip]

It appears that 14.8.2.4 covers the deduction rules in this case.

I understand you trying to avoid using a template argument list.
Is there any reason you don't want to specify the type conversion
explicitly? I would just do this:

A<int> a(5);
do_something(static_cast<B<int> >(a));

Denis
 
B

bartek

bartek said:
Please consider the following scenario below (sketch of).
There are two templates defined: A and B, both with mutual conversion
operators defined.
Also, there's a free function template 'do_something' with the
following signature:

template <class T>
inline void do_something(B<T> const& arg);

Now, given an object of type, say, A<int> passed as a parameter to
that function, the compiler gives up when deducing template
arguments. Is it possible to somehow go around this, without using
explicit template specification? It's a show-stopper for templated
operators.
[snip]

It appears that 14.8.2.4 covers the deduction rules in this case.

I understand you trying to avoid using a template argument list.
Is there any reason you don't want to specify the type conversion
explicitly? I would just do this:

A<int> a(5);
do_something(static_cast<B<int> >(a));

Well, this could be the last resort... I hope it could be done
automatically though.

Say, the class B<T> provides const-reference semantics for A<T>, so both
of them are very closely related, and I'd like it to behave exactly like
the built-in reference in the same context.
 
B

bartek

bartek wrote in
in
comp.lang.c++:


The compiler can't deduce that a B<T> is called for when given an


There's a whole bunch of tricks you can use, I wouldn't describe
any of them as simple though.

This is about the most straight forward though:

template < typename T >
struct arg_from_template;

template < typename T, template <typename> class C >
struct arg_from_template< C< T > >
{
typedef T type;
};

template < typename T >
void do_something( T const &arg )
{
typedef typename arg_from_template< T >::type real_T;
typedef B< real_T > b_type;

b_type const &real_arg = arg;

// Do whatever with real_arg ...
}

Thanks. That's an option.
However, wouldn't do_something() eat arguments of any type now?
If do_something() was actually, say, templated basic_ostream insert
operator, it wouldn't be OK, would it?

My example code was too vague, I think...
Actually, I'd like class B to implement reference behaviour for class A.

Thanks.
 
R

Rob Williscroft

bartek wrote in in comp.lang.c++:
Thanks. That's an option.
However, wouldn't do_something() eat arguments of any type now?
If do_something() was actually, say, templated basic_ostream insert
operator, it wouldn't be OK, would it?

Well A simple trick in that case would be to use ADL

namespace stuff
{
// A...
// B...

template < typename Ch, typename Al, typename T >
std::basic_ostream< Ch, Al > &
operator( std::basic_ostream< Ch, Al > &os, T const &arg )
{
}
}

using stuff::A;
using stuff::B;

// *NOT* using namespace stuff;


int main()
{
A< int > ai;

std::cout << ai;
}

My example code was too vague, I think...
Actually, I'd like class B to implement reference behaviour for class
A.

If you only have the two class-templates, A and is "reference" B,
then I'd go with just typing the second overload:

template < typename Ch, typename Al, typename T >
inline std::basic_ostream< Ch, Al > &
operator( std::basic_ostream< Ch, Al > &os, A< T > const &arg )
{
return os << static_cast< B< T > >( arg );
}

It more typing but less fafing about :).

Rob.
 
S

Siemel Naran

bartek said:
Say, the class B<T> provides const-reference semantics for A<T>, so both
of them are very closely related, and I'd like it to behave exactly like
the built-in reference in the same context.

For this, people often provide a non-explicit constructor B<T>::B(const
A<T>&).

But you say you want a conversion from A<T> to B<T>, and vice versa. What
case is this?
 

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,811
Messages
2,569,693
Members
45,477
Latest member
IsidroSeli

Latest Threads

Top