C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Implicit conversions, function templates -- an unholy allian

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Glen Low
Guest





PostPosted: Fri Aug 20, 2004 12:20 am    Post subject: Implicit conversions, function templates -- an unholy allian Reply with quote



Suppose we have two templates that can be implicitly converted (by the
appropriate non-templated conversion constructor or conversion
operator):

A <T> -> B <T>


I have a basic operation that works on B instances like this:

template <typename T1, typename T2> void op (B <T1>, B <T2>);

Now because it is a function template, it must match exactly the
arguments passed and will not do any implicit conversions for you,
therefore:

A <T1> at1;
B <T2> bt2;

op (at1, bt2);

.... doesn't work even though at1 is convertible to a B <T1>.

How do I arrange for all the sensible combinations of A and B to work,
other than defining op for all such combinations e.g.

A <T1> at1;
A <T2> at2;
B <T1> bt1;
B <T1> bt2;

op (at1, at2)
op (at1, bt2)
op (bt1, at2)

.... should all work.

Prior art and other seeming nudges along the right path that only
serve to irritate when the result is still past one's grasp:

1. std::string and const char* have this relationship, but operator==
in most std library implementations etc. go ahead and define all the
combinations thereof.

2. Ditto std::complex <T> and T.

3. I was rather fond of Mr. Barton and Mr. Nackman, but alas they only
work if there is only one template type e.g.

template <typename T> struct B
{
....
friend void op (B <T>, B <T>);
};

Lo and behold, C++ now honors the conversion because op is no longer a
function template.

4. Got 60% of my neurons tied up in SFINAE to no avail (as yet).

I await your collective wisdom.

Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Maxim Yegorushkin
Guest





PostPosted: Fri Aug 20, 2004 1:45 pm    Post subject: Re: Implicit conversions, function templates -- an unholy al Reply with quote



Glen Low wrote:

Quote:
Suppose we have two templates that can be implicitly converted (by the
appropriate non-templated conversion constructor or conversion
operator):

A <T> -> B <T

I have a basic operation that works on B instances like this:

template
Now because it is a function template, it must match exactly the
arguments passed and will not do any implicit conversions for you,
therefore:

A <T1> at1;
B <T2> bt2;

op (at1, bt2);

... doesn't work even though at1 is convertible to a B <T1>.

How do I arrange for all the sensible combinations of A and B to work,
other than defining op for all such combinations e.g.

A <T1> at1;
A <T2> at2;
B <T1> bt1;
B <T1> bt2;

op (at1, at2)
op (at1, bt2)
op (bt1, at2)

... should all work.

[]

Quote:
4. Got 60% of my neurons tied up in SFINAE to no avail (as yet).

SFINAE really helps here:

#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/mpl/and.hpp>

// here A<T> and B<T> are convertible to C<T>

template<class T>
struct A
{
typedef T arg_t_1;
};

template<class T>
struct B
{
typedef T arg_t_1;
};

template<class T>
struct C
{
typedef T arg_t_1;

C();
C(A<T> const&);
C(B<T> const&);
};

// this template does all the work
template<class T, class U> void op(C<T>, C<U>);

// this one is the forwarder
// it kicks in only when its arguments provide arg_t_1 typedefs and are convertible to C<arg_t_1>
template<class T, class U>
typename boost::enable_if<
boost::mpl::and_<
boost::is_convertible
, boost::is_convertible<U, C
Quote:

, void
::type op(T const& t, U const& u)
{

return op(
static_cast<C(t)
, static_cast<C(u)
);
}

void f()
{
A <char> a1;
A <int> a2;
B <char> b1;
B <int> b2;
C <char> c1;
C <int> c2;

op(a1, a2);
op(b1, b2);
op(c1, c2);

op(a1, c1);
op(b1, c1);
op(a2, c1);
op(b2, c1);

op(0, c1); // oops! no matching function for call to `op(int, C<char>&)'
}

--
Maxim Yegorushkin

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
David Abrahams
Guest





PostPosted: Fri Aug 20, 2004 2:35 pm    Post subject: Re: Implicit conversions, function templates -- an unholy al Reply with quote



[email]glenlow (AT) pixelglow (DOT) com[/email] (Glen Low) writes:

Quote:
Suppose we have two templates that can be implicitly converted (by the
appropriate non-templated conversion constructor or conversion
operator):

A <T> -> B <T


I have a basic operation that works on B instances like this:

template
Now because it is a function template, it must match exactly the
arguments passed and will not do any implicit conversions for you,
therefore:

A <T1> at1;
B <T2> bt2;

op (at1, bt2);

... doesn't work even though at1 is convertible to a B <T1>.

How do I arrange for all the sensible combinations of A and B to work,
other than defining op for all such combinations e.g.

A <T1> at1;
A <T2> at2;
B <T1> bt1;
B <T1> bt2;

op (at1, at2)
op (at1, bt2)
op (bt1, at2)

How do you decide what "sensible" is? There's not enough info here.
Quote:

Prior art and other seeming nudges along the right path that only
serve to irritate when the result is still past one's grasp:

1. std::string and const char* have this relationship, but operator==
in most std library implementations etc. go ahead and define all the
combinations thereof.

2. Ditto std::complex <T> and T.

3. I was rather fond of Mr. Barton and Mr. Nackman, but alas they only
work if there is only one template type e.g.

template <typename T> struct B
{
...
friend void op (B <T>, B <T>);
};

Lo and behold, C++ now honors the conversion because op is no longer a
function template.

4. Got 60% of my neurons tied up in SFINAE to no avail (as yet).

Not sure precisely what you're after, but I think we solved a similar
problem with SFINAE for boost::iterator_facade:

template <typename T1, typename T2>
boost::enable_if<
boost::mpl::or_<
boost::is_convertible
, boost::is_convertible<B
Quote:

::type
op (B <T1>, B <T2>);


This is an op that matches only if B<T1> is convertible to B<T2>, or
vice-versa.

--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
kwikius
Guest





PostPosted: Sat Aug 21, 2004 4:14 am    Post subject: Re: Implicit conversions, function templates -- an unholy al Reply with quote

[email]glenlow (AT) pixelglow (DOT) com[/email] (Glen Low) wrote in message news:<9215d7ac.0408182235.3a3587d7 (AT) posting (DOT) google.com>...
Quote:
Suppose we have two templates that can be implicitly converted (by the
appropriate non-templated conversion constructor or conversion
operator):

A <T> -> B <T


I have a basic operation that works on B instances like this:

template
Now because it is a function template, it must match exactly the
arguments passed and will not do any implicit conversions for you,
therefore:

A <T1> at1;
B <T2> bt2;

op (at1, bt2);

... doesn't work even though at1 is convertible to a B <T1>.

How do I arrange for all the sensible combinations of A and B to work,
other than defining op for all such combinations e.g.

A <T1> at1;
A <T2> at2;
B <T1> bt1;
B <T1> bt2;

op (at1, at2)
op (at1, bt2)

// tested VC7.1 , gcc 3.2
#include <iostream>
#include "boost/utility/enable_if.hpp"
template<typename T>
class A{};
template <typename T>
class B{};
//make condition::value false on A,B to disable
template <typename A, typename B>
struct condition
{
static const bool value = true;
};

template <typename T1, typename T2>
typename boost::enable_if<condition::type op (B<T1>, B<T2>)
{
std::cout << "firstn";
}
template<
template template<typename> class UDTb,
typename Value_typeA,
typename Value_typeB
Quote:

inline

typename boost::enable_if<condition >::type
op(UDTa<Value_typeA> const & a,UDTb<Value_typeB> const & b)
{
std::cout << "secondn";
}

int main()
{
A B<double > b;
op(a,a); // second
op(b,b); // first
op(a,b); // second
op(b,a); // second
}

regards
Andy Little

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Glen Low
Guest





PostPosted: Sat Aug 21, 2004 10:20 am    Post subject: Re: Implicit conversions, function templates -- an unholy al Reply with quote

Quote:
How do you decide what "sensible" is? There's not enough info here.

Perhaps I shall attempt to tighten up the spec and simultaneously be
more general, if possible.

I have a template A, whose instances can be implicitly converted from
some arbitrary types. Now these types could be classes but they can
also be inbuilts. Say for example, we have:

U -> A <int>
V -> A <int>
W -> A <char>

etc.

I define an binary function between A <T1> and A <T2>. Because it is
templated on T, it *has* to be a function template e.g.

template <typename T1, typename T2> void f (A <T1>, A <T2>);

Now for a particular case, all the combinations of A <T> and the types
it converts from should work identically to the above function
template e.g.

For T1 = int and T2 = char, I want the following combinations to work:

f (A <int>, A <char>)
f (U, A <char>)
f (V, A <char>)
f (A <int>, W)

It is sufficient that at least one of the arguments is an instance of
the A template.

There may be issues of ambiguity, especially if a type Z converts to
both A <T1> and A <T2> -- presumably this was the motivation behind
function templates needing to match exactly their arguments rather
than regular functions -- but then I want an overload ambiguity to
arise then or some other kind of compile-time error.

I could of course, exhaustively and manually define all the
combinations thereof, but it seems rather tedious, error-prone coding,
and it gets worse with ternary and higher-order functions.

Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Glen Low
Guest





PostPosted: Sat Aug 21, 2004 10:20 am    Post subject: Re: Implicit conversions, function templates -- an unholy al Reply with quote

Quote:
// this one is the forwarder
// it kicks in only when its arguments provide arg_t_1 typedefs and are convertible to C<arg_t_1
template typename boost::enable_if
boost::mpl::and_
boost::is_convertible , boost::is_convertible
, void
::type op(T const& t, U const& u)
{
return op(
static_cast(t)
, static_cast<C(u)
);
}

Pretty good, except that
1. The types T and U may not be class types and even if they were you
might not be able to change them.
2. The real kicker is that one type may convert to two or more C <T>
types, but the arg_t_1 typedef seems to indicate a convert to only one
C <T> type. Of course that should result in an overload ambiguity for
those types and those types only.

Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Maxim Yegorushkin
Guest





PostPosted: Sun Aug 22, 2004 3:13 am    Post subject: Re: Implicit conversions, function templates -- an unholy al Reply with quote

Glen Low <glenlow (AT) pixelglow (DOT) com> wrote:

[]

Quote:
1. The types T and U may not be class types and even if they were you
might not be able to change them.

Regular traits might help you here (something like is_convertible_to_C<>), from which you can also pull out the C<U> type for given T.

Quote:
2. The real kicker is that one type may convert to two or more C <T
types, but the arg_t_1 typedef seems to indicate a convert to only one
C those types and those types only.

If there exist more than one conversion (T -> C<U>, T -> C<V>) and no one is better than the other, than the regular solution is that the user resolves the ambiguity manually.

--
Maxim Yegorushkin

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Carl Barron
Guest





PostPosted: Sun Aug 22, 2004 3:29 am    Post subject: Re: Implicit conversions, function templates -- an unholy al Reply with quote

In article <9215d7ac.0408202312.2787199d (AT) posting (DOT) google.com>, Glen Low
<glenlow (AT) pixelglow (DOT) com> wrote:

Quote:
// this one is the forwarder
// it kicks in only when its arguments provide arg_t_1 typedefs and are
convertible to C<arg_t_1
template typename boost::enable_if
boost::mpl::and_
boost::is_convertible , boost::is_convertible
, void
::type op(T const& t, U const& u)
{
return op(
static_cast(t)
, static_cast<C(u)
);
}

Pretty good, except that
1. The types T and U may not be class types and even if they were you
might not be able to change them.
solution here is a compile time function to get the equivalent;


template <typename T> struct ArgType
{
typedef typename T::arg_1 type;
};

specialize for classes you can't modify and non class types.

use ArgType<T>::type for T::arg_t_1 above in op.

now if there is no overload template <class T,class U> void op(C<T>
const &,C<U> const &) this will recurse indefinitelty.

Quote:
2. The real kicker is that one type may convert to two or more C <T
types, but the arg_t_1 typedef seems to indicate a convert to only one
C those types and those types only.

If this problem occurs specialize ArgType for these types to

disambiguate them. [if possible]

Quote:
Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Glen Low
Guest





PostPosted: Mon Aug 23, 2004 10:29 am    Post subject: Re: Implicit conversions, function templates -- an unholy al Reply with quote

Quote:
1. The types T and U may not be class types and even if they were you
might not be able to change them.

Regular traits might help you here (something like is_convertible_to_C<>), from which you can also pull out the C<U> type for given T.

It still is somewhat of a horse-before-carriage thing.

Given a function template like this

template <typename T, typename U> ??? op (const T& t, const U& u)

I do not know what possible C<X> types a T converts to, since an
arbitrary T could convert to one or more such C<X> types. (In the case
that T converts to more than one C<X> type, then it is fine that some
kind of overload ambiguity or other compile-time error arises.)

The best I can do is limit to *one* the types that C<X> converts
*from*, perhaps declared in a member typedef like C<X>::data_type.

Essentially, the relation between an arbitrary type T and all
instances of the C template is one-to-many.

Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.