function template

D

Denis Remezov

Pete said:
That's the result of the ?: operator, regardless of whether you use it
directly in your code, through a macro, or through a template. Since one
argument is unsigned and the other float, the unsigned is converted to
float. Its value is not exactly representable on your system.

Oh well, I understand that. The point was that you cannot always rely
on the compiler to do the "right" promotion automatically. Sometimes
you need to do that semi-manually (e.g. via type traits).
I, at least, cannot see how you can do it automatically in a standard
way.

Denis
 
P

Pete Becker

Denis said:
The output that I receive with several compilers is:
a: 4294967295
x: 4294967296.000000

This is not what I want.

That's the result of the ?: operator, regardless of whether you use it
directly in your code, through a macro, or through a template. Since one
argument is unsigned and the other float, the unsigned is converted to
float. Its value is not exactly representable on your system.
 
G

Gianni Mariani

Pete Becker wrote:
....
I've said nothing about traits classes. What I said is that writing
N*(N-1) template specializations to handle all pairs of N argument types
isn't my idea of clean code. I prefer to let the compiler do that kind
of work -- it's much better at it. (Note that the sample implementation
doesn't get the platform-dependent promotion semantics right, while the
compiler almost certainly does).

Time for typeof() then ?
 
P

Pete Becker

Gianni said:
Pete Becker wrote:
...

Time for typeof() then ?

Maybe. But that answers a different question: "How might I write this
code in the future?", versus "How can I write this code?" Which was your
original point...
 
P

Pete Becker

Denis said:
Oh well, I understand that. The point was that you cannot always rely
on the compiler to do the "right" promotion automatically. Sometimes
you need to do that semi-manually (e.g. via type traits).

If by "the 'right' promotion" you mean that you can't rely on the
compiler to do something other than what it's supposed to do, I suppose
you're right. The compiler follows the language rules. If you don't want
the result that the language rules provide for ?: then you have to write
code that does something different. Saying the magic words "type traits"
doesn't change that.
 
D

Denis Remezov

Pete said:
If by "the 'right' promotion" you mean that you can't rely on the
compiler to do something other than what it's supposed to do, I suppose
you're right. The compiler follows the language rules. If you don't want
the result that the language rules provide for ?: then you have to write
code that does something different. Saying the magic words "type traits"
doesn't change that.

I couldn't figure out what it doesn't change. Maybe I'm dyslexic.


template <typename T0, typename T1>
struct promote {};

//platform-dependent
template <>
struct promote<unsigned int, float> {
typedef double type;
};

//...

template <typename T_arg0, typename T_arg1>
typename promote<T_arg0, T_arg1>::type find_max(T_arg0 x, T_arg1 y) {
typedef typename promote<T_arg0, T_arg1>::type T_ret;
T_ret xp = (T_ret)x;
T_ret yp = (T_ret)y;
return xp > yp? xp : yp;
}

Denis
 
J

Jeff Schwab

Pete said:
At changing the subject.

That wasn't my intent.
Look again: every one of those approximately 100 specialiations is
needed. Every time you compare two objects of different types you need a
specialization. The default implementation only handles objects of the
same type. And that's the problem: this approach requires a
specialization for every pair of distinct types.

Not so. Get the Josuttis book on templates and read the chapter will he
covers exactly this case (Promotion_traits).
No, this approach requires a template specialization for every pair of
distinct types that the program compares.

That's not true.
I didn't say "for all new types". I said "for any additional types YOU
WANT TO SUPPORT." (emphasis added for the reading impaired)

Getting upset and yelling won't help.

I read what you wrote, and I responded to what you seemed to mean. I'm
sorry for any confusion on my part.

Anyway, it's still not true. As a naive first pass, a default template
to find the minimum of two values of different types might just choose
the larger type, as determined by sizeof. This won't always do the
right thing, but it's a reasonable default.
The original question, if you recall, was about handling pairs of
arguments of different types. This approach requires a template
specialization for every such pair. So, yes, it's "only" those types,
but they're the only ones that are interesting. Handling pairs of the
same type is simple.




Word games.

No, meaningful distinctions.
Adding stuff in order to make your template work is
maintenance, regardless of whether it's "sold separately."

Why do you think of it as "adding stuff?" Traits classes needing
specialization for a given type aren't just add-ons.
Not that it's
at all clear why someone would be selling these things: the question was
how to write a template that compares two objects of different types,
and the proposed solution consists of a long list of template
specializations. Who do you think is going to sell template
specializations for class MyType?

The designer or vendor of class MyType, if not someone else.
And how will they know that you need
to compare Mytype and YourType objects, so they can provide the
appropriate specializations?

They don't have to know that. At a minimum, they might specialize the
traits classes that are already part of the standard library (if
necessary), e.g. numeric_limits for a large integer type. If a vendor
also is providing a way to compare two values of a given type, it seems
reasonable that they might also specialize a common traits classes
related to comparisons, e.g. Promotion_traits. Of course, a client also
can request particular specializations, just as they might request any
other part of an interface explicitly.
I've said nothing about traits classes. What I said is that writing
N*(N-1) template specializations to handle all pairs of N argument types
isn't my idea of clean code.

That may be what you meant, but it's not what you said.
I prefer to let the compiler do that kind
of work -- it's much better at it.

Not so. The compiler does the right thing in many, but not all, cases.
(Note that the sample implementation
doesn't get the platform-dependent promotion semantics right, while the
compiler almost certainly does).

Then platform-dependent types should rely on the compiler to do the
right thing. The compiler won't always do the right thing, though, and
it should be possible for users to specialize the cases without changing
the user-visible interface.
 
S

Sergiy Kanilo

Not so. Get the Josuttis book on templates and read the chapter will he
covers exactly this case (Promotion_traits).

If the resulting type of operator could be only type of one of the operand
it is possible IMHO to go without traits. Something like

template<bool Cond,typename T,typename U> struct If{ typedef T type; };
template<typename T,typename U> struct If<false,T,U>{ typedef U type; };

template<typename T,typename U>
struct CondOp
{
static char (&helper(T,U ...))[1];
static char (&helper(T,U,U))[2];
static T t();
static U u();
typedef typename If< sizeof( helper( t(), u(), 0 ? t() : u() ) )==1, T, U
::type type;
};

template<typename T,typename U>
typename CondOp<T,U>::type max(T a,U b)
{
return a>b ? a: b;
}

Cheers,
Serge
 
P

Pete Becker

Jeff said:
Anyway, it's still not true. As a naive first pass, a default template
to find the minimum of two values of different types might just choose
the larger type, as determined by sizeof. This won't always do the
right thing, but it's a reasonable default.

Sigh. I was talking about the templates in Gianni's original message,
which is the approach that you said you liked. Now you say its
weaknesses are solved by yet another approach, with yet another set of
weaknesses. Sorry, I'm not going to play any longer.
 
P

Pete Becker

Denis said:
I couldn't figure out what it doesn't change. Maybe I'm dyslexic.

No, but you didn't say what you had in mind. The discussion was about
determining the return type, and changing that doesn't affect the type
that ?: produces.
 
J

Jeff Schwab

Pete said:
Sigh. I was talking about the templates in Gianni's original message,
which is the approach that you said you liked. Now you say its
weaknesses are solved by yet another approach, with yet another set of
weaknesses.

That is not what I said. I like Gianni's approach just fine. The
problem you claimed with the approach was that new specializations would
need to be provided for any possible pair of types whose values would be
compared. That's not true.
Sorry, I'm not going to play any longer.

Don't be sorry. I'm not.
 
P

Pete Becker

Jeff said:
That is not what I said. I like Gianni's approach just fine. The
problem you claimed with the approach was that new specializations would
need to be provided for any possible pair of types whose values would be
compared. That's not true.

Okay, time for the bottom line.

#define findMin(x, y) (((x) < (y)) ? (x) : (y))

This took about thirty seconds to write. It works for all sensible
types. Its limitations can be expressed in a simple declarative
sentence: arguments should not have side effects. It's simple enough
that its correctness can be determined by inspection.

Your solution starts with a template specialization for arguments of the
same type, plus about a hundred specializations for mixed arithmetic
types. As written it gives wrong answers on some platforms. Your
solution for additional arithmetic types is that library vendors will do
whatever is needed. You haven't addressed the portability problem.
You've also suggested that additional types can be accommodated by
adding "default" templates, perhaps using sizeof as a first cut, but you
haven't provided that code. In short, you don't have a complete
implementation and you don't have a design specification. As a result,
it's not possible to assess how well your solution works, nor what its
limitations are. Further, testing this brute force solution will require
a brute force test suite, and it will require testing on every compiler
that you want to use.

The macro is clearly the better solution.
 

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

Forum statistics

Threads
474,169
Messages
2,570,920
Members
47,464
Latest member
Bobbylenly

Latest Threads

Top