 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Glen Low Guest
|
Posted: Fri Aug 20, 2004 12:20 am Post subject: Implicit conversions, function templates -- an unholy allian |
|
|
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
|
Posted: Fri Aug 20, 2004 1:45 pm Post subject: Re: Implicit conversions, function templates -- an unholy al |
|
|
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
|
Posted: Fri Aug 20, 2004 2:35 pm Post subject: Re: Implicit conversions, function templates -- an unholy al |
|
|
[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
|
Posted: Sat Aug 21, 2004 4:14 am Post subject: Re: Implicit conversions, function templates -- an unholy al |
|
|
[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
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
|
Posted: Sat Aug 21, 2004 10:20 am Post subject: Re: Implicit conversions, function templates -- an unholy al |
|
|
| 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
|
Posted: Sat Aug 21, 2004 10:20 am Post subject: Re: Implicit conversions, function templates -- an unholy al |
|
|
| 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
|
Posted: Sun Aug 22, 2004 3:13 am Post subject: Re: Implicit conversions, function templates -- an unholy al |
|
|
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
|
Posted: Sun Aug 22, 2004 3:29 am Post subject: Re: Implicit conversions, function templates -- an unholy al |
|
|
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]
[ 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
|
Posted: Mon Aug 23, 2004 10:29 am Post subject: Re: Implicit conversions, function templates -- an unholy al |
|
|
| 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 |
|
 |
|
|
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
|
|