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 

std::pair<>::operator+ template deduction
Goto page 1, 2  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Joshua Lehrer
Guest





PostPosted: Sat Sep 20, 2003 10:07 am    Post subject: std::pair<>::operator+ template deduction Reply with quote



I was writing a program and I needed to be able to add two pairs
together. I was surprised to discover that std::pair has no operator+
defined. After sitting down and trying to write one, I believe I have
discovered why... it is really tough.

The problem lies in what would be the return value of the operator:

template <typename T1, typename T2, typename T3, typename T4>
???? operator+(const std::pair<T1,T2> &p1, const std::pair<T3,T4>
&p2);

When adding pairs of like types, the return type is obvious. However,
when adding a pair<int,float> to a pair<float,int>, the return type
should be pair<float,float>.

The result should pair<T1+T3,T2+T4>. In other words, the first result
type is whatever adding a T1 and a T3 would return. Likewise for the
second type of the return.

I attempted to implement this using template magic. Unfortunately, I
receive a very strange error from my compiler that I can not
understand, and, obviously, can't fix.

Comeau fails to compile with the error:

ComeauTest.c", line 49: error: no operator "+" matches these operands
operand types are: std::pair<float, int> + std::pair<int,
unsigned
int>
p1+p2;
^

My compiler (Compaq C++ V6.5-038) gives the following cryptic error:

p1+p2;
........^
%CXX-E-BADTYPFROMINST, template instantiation resulted in unexpected
function type of "std::pair<Choose Choose<false, int, unsigned int>::result> (const std::pair<float,
int> &, const std::pair<int, unsigned int> &)" (the meaning of a
name may have changed since the template declaration -- the type
of the template is "std::pair<Choose<::result,
Choose<::result> (const std::pair<T1, T2> &,
const std::pair<T3, T4> &)") detected during instantiation of
"operator+" based on template arguments <float, int, int, unsigned
int> at line 49

Can anyone help? Here is the code:

#include <utility>

//template to choose between two types given
//a boolean test
template <bool flag, typename T1, typename T2> struct Choose {
typedef T1 result;
};
template <typename T1, typename T2> struct Choose<false,T1,T2> {
typedef T2 result;
};

//template to help determine what the result of
//a function call would be, either T1 or T2
template <typename T1, typename T2>
struct pair_helper {
struct first { char c; };
struct second { first c[2]; };

char check_condition[(sizeof(first)==sizeof(second)) ? 0 : 1];

static first func(const T1&);
static second func(const T2&);
};

//specialization of above when
//T==T
template <typename T>
struct pair_helper <T,T> {
typedef char first;
static first func(const T&);
};

//a global version of operator+ for two pairs
//determine return type at compile time
template <typename T1, typename T2, typename T3, typename T4>
inline
std::pair<
typename Choose *((T3*)0))) == sizeof(pair_helper<T1,T3>::first),T1,T3>::result,
typename Choose<sizeof(pair_helper *((T4*)0))) == sizeof(pair_helper<T2,T4>::first),T2,T4>::result
Quote:

operator+(const std::pair<T1,T2> &p1,

const std::pair<T3,T4> &p2) {
return std::make_pair(p1.first+p2.first , p1.second+p2.second);
}

int main(int argc, char **argv) {
std::pair<float,int> p1(1,1);
std::pair<int,unsigned int> p2(2.5,2);
p1+p2;
}


joshua lehrer
factset research systems
NYSE:FDS

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

Back to top
Siemel Naran
Guest





PostPosted: Sun Sep 21, 2003 10:21 am    Post subject: Re: std::pair<>::operator+ template deduction Reply with quote



"Joshua Lehrer" <usenet_cpp (AT) lehrerfamily (DOT) com> wrote in message

Quote:
I was writing a program and I needed to be able to add two pairs
together. I was surprised to discover that std::pair has no operator+
defined. After sitting down and trying to write one, I believe I have
discovered why... it is really tough.

That's why we need typeof Smile.


Your code looks workable, yet on Borland 6 I get this error

[C++ Error] Unit1.cpp(19): E2109 Not an allowed type

which I've nailed down as a bug in the compiler. On g++ 2.95

x.cc: In function `int main(int, char **)':
x.cc:44: Internal compiler error.

which is almost certainly a bug in the compiler. Someone would g++
3.whatever might have better luck Smile.


On 6/29 I posted a response to a subject titled "Typeof workaround". There
were some replies. You can find the original on Google if you have time.

Newsgroups: comp.lang.c++.moderated
Sent: Sunday, June 29, 2003 1:54 PM
Subject: Re: Typeof workaround

=======================================

"Nicolas Fleury" <nid_oizo (AT) yahoo (DOT) com_removethe_> wrote


Quote:
template <typename X, typename Y
MyClass


Start with template_if

template <bool cond, class A, class B>
struct template_if
{
};

template <class A, class B>
struct template_if<true,A,B>
{
typedef A result;
};

template <class A, class B>
struct template_if<false,A,B>
{
typedef B result;
};


Now create your plustype<X,Y> that captures the type of X+Y in a typedef.

template <class X, class Y>
struct plustype{
typedef X first;
typedef Y second;
typedef typename template_if<sizeof(X()+Y())==sizeof(X), X, Y>::result
result;
};

Assumptions:

(1) In X+Y, type of result is either X or Y. For the exceptions to this
rule users can specialize plustype.

(2) X and Y have different sizeof. Unfortunately this means plustype will
fail for X == signed int and Y == unsigned int, where the result should be Y
or unsigned int because unsigned takes precedence, but will be X. Perhaps
std::numeric_limits<T>::is_signed would help for cases like these. So how
should we define struct plustype now?

(3) X and Y have default constructors. For types that we are add, like int
and double, the assumption makes sense.


Then write your operator+.

template <typename X, typename Y>
MyClass<typename plustype
operator+(const MyClass<X>&, const MyClass<Y>&);

=======================================

For your code replace the last 3 lines with

template <typename T1, typename T2, typename T3, typename T4>
inline
std::pair<
typename plustype typename plustype<T2,T4>::result
Quote:

operator+(const std::pair<T1,T2> &p1,

const std::pair<T3,T4> &p2) {
return std::make_pair(p1.first+p2.first , p1.second+p2.second);
}

I don't know why the above works but your original does not. It seems that
the compiler does not like complex expressions for the stuff in <angle
brackets>. Essentially I've moved the complex expression you had into a new
class that can be parsed seperately. I also don't think you need the sizeof
stuff.

To test add these lines

#include <iostream>
#include <typeinfo>

template <class T>
void test(const T&) {
std::cout << typeid(T).name() << 'n';
}

int main(int argc, char **argv) {
std::pair std::pair<int,unsigned int> p2(2.5,2);
test(p1+p2);
}

Unfortunately on g++ it prints

[default@TINY] [~/tmp] >> g++ --pedantic y.cc

[default@TINY] [~/tmp] >> a
t4pair2ZfZi

=======================================

Quote:
//a global version of operator+ for two pairs
//determine return type at compile time
template <typename T1, typename T2, typename T3, typename T4
inline
std::pair
typename Choose *((T3*)0))) == sizeof(pair_helper<T1,T3>::first),T1,T3>::result,
typename Choose<sizeof(pair_helper *((T4*)0))) == sizeof(pair_helper<T2,T4>::first),T2,T4>::result

operator+(const std::pair<T1,T2> &p1,
const std::pair<T3,T4> &p2) {
return std::make_pair(p1.first+p2.first , p1.second+p2.second);
}

The same two objections apply.

(1) In X+Y, type of result is either X or Y. This may not always be the
case.

(2) X and Y have different sizeof. But they may be different types with the
same sizeof, as in X==signed int and Y==unsigned int.

--
+++++++++++
Siemel Naran


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

Back to top
Markus Werle
Guest





PostPosted: Mon Sep 22, 2003 10:25 pm    Post subject: Re: std::pair<>::operator+ template deduction Reply with quote



Joshua Lehrer wrote:

Quote:
I was writing a program and I needed to be able to add two pairs
together. I was surprised to discover that std::pair has no operator+
defined. After sitting down and trying to write one, I believe I have
discovered why... it is really tough.

I cannot remember why your code fails to compile.

The main issue is to determine a correct return type,
even for complicated expressions, and I think your approach is
a little bit broken, therefore see my code below.

I also tried to use my Expression Template framework (Daixtrose)
to see how it fits. IMHO it fits well. Enjoy (and copy, it's copylefted)

ATTN: the code is untested and contains at least 1 bug :-)

Markus

// Copyright (C) 2003 Markus Werle
//
// The code below will be part of the examples section of the
// Daixtrose C++ Library.
// This library is free software;
// you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the
// Free Software Foundation; either version 2.1, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public License
// along with this library; see the file COPYING. If not, send mail to the
// developers of daixtrose (see e.g. http://daixtrose.sourceforge.net/)

// As a special exception, you may use this file as part of a free software
// library without restriction. Specifically, if other files instantiate
// templates or use macros or inline functions from this file, or you
compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered by
// the GNU Lesser General Public License. This exception does not however
// invalidate any other reasons why the executable file might be covered by
// the GNU Lesser General Public License.



// ==================================================================

// Admittedly this code example is shooting with the bazookas, but this
// code is easy to extend. It also serves as an example on how to use
// Daixtrose. Feel free to send me some critique about its design or
// interface etc.

// Sorry, this example needs boost, loki (due to lack of time to remove
// deps) and daixtrose-cvs. Happy download y'all

#include <iostream>
#include <utility>

// obtain from http://www.boost.org
#include "boost/mpl/apply_if.hpp"
#include "boost/mpl/identity.hpp"
#include "boost/type_traits.hpp"

// obtain from http://daixtrose.sf.net
// please use CVS !!!, new release coming soon:
#include "daixtrose/Daixt.h"

// shortcut
namespace mpl = boost::mpl;


namespace My
{

////////////////////////////////////////////////////////////////////////////
// traits for simple types

// unary ops

template <typename T, typename UnOp>
struct return_type_of_unop;

// minus does not change the type
template <typename T>
struct return_type_of_unop<T, Daixt::DefaultOps::UnaryMinus>
{
typedef T type;
};

// ... to be continued


// binary ops

template <typename T1, typename T2, typename BinOp>
struct return_type_of_binop;

// FIXIT: incomplete; put all your refined headache here.


// And now: eyes wide shut
template <typename T1, typename T2>
struct return_type_of_binop<T1, T2, Daixt::DefaultOps::BinaryPlus>
{
struct Error_in_type_detection_mechanism;

// the larger one of both types:
typedef mpl::apply_if_c<
(sizeof(T1) < sizeof(T2)),
mpl::identity mpl::identity<T1>
Quote:
the_larger_type;

typedef typename
// if T1 and T2 are the same
mpl::apply_if_c<boost::is_same
mpl::identity<T1>,

// else: if T1 is convertible to T2 and T2 is convertible
to
// T1 the return type is the one with largest storage


mpl::apply_if_c<(boost::is_convertible &&
boost::is_convertible<T1,T2>::value),

the_larger_type,

// else if T1 is convertible to T2 and
// sizeof(T1) < sizeof(T2) return type
is T2
mpl::apply_if_c<
(boost::is_convertible &&
sizeof(T1) < sizeof(T2)),

mpl::identity
// else
// if T2 is convertible to T1
// and sizeof(T2) < sizeof(T1)
// return type is T1
mpl::apply_if_c<
(boost::is_convertible &&
sizeof(T2) < sizeof(T1)),

mpl::identity
mpl::identity
<Error_in_type_detection_mechanism>
Quote:



::type type; // phew!
};


// ... to be continued


//////////////////////////////////////////////////////////////////////////////

// communicate with Daixtrose

// disambiguation (the odd stuff for small examples, but useful
// if You do a lot of different Expression Template stuff in the
// same translation unit

struct StdPairOps {};

} // namespace My

namespace Daixt
{
template <typename T1, typename T2>
struct Disambiguator<std::pair
{
enum { is_specialized = true };
typedef My::StdPairOps Disambiguation;
};
}



// the hard work to be done once for all times, if you wanna use Daixtrose
namespace My {

// determination of result types for pair ops
template <typename T> struct pair_result_traits
{
typedef T type; // default: no change
};

template <typename ARG, typename OP>
struct pair_result_traits<Daixt::UnOp
{
typedef typename pair_result_traits<ARG>::type arg_type;

typedef typename arg_type::first_type arg_type_1;
typedef typename arg_type::second_type arg_type_2;

typedef typename return_type_of_unop<arg_type_1, OP>::type _1;
typedef typename return_type_of_unop<arg_type_2, OP>::type _2;

typedef std::pair<_1, _2> type;
};

template <class LHS, class RHS, class OP>
struct pair_result_traits<Daixt::BinOp
{
typedef typename pair_result_traits<LHS>::type lhs_arg_type;
typedef typename pair_result_traits<RHS>::type rhs_arg_type;

typedef typename lhs_arg_type::first_type lhs_arg_type_1;
typedef typename lhs_arg_type::second_type lhs_arg_type_2;
typedef typename rhs_arg_type::first_type rhs_arg_type_1;
typedef typename rhs_arg_type::second_type rhs_arg_type_2;

typedef typename return_type_of_binop
<lhs_arg_type_1, rhs_arg_type_1, OP>::type _1;

typedef typename return_type_of_binop
<lhs_arg_type_2, rhs_arg_type_2, OP>::type _2;

typedef std::pair<_1, _2> type;
};


struct Evaluator
{
// simplest first: reach through
template <typename T1, typename T2>
inline std::pair<T1, T2> const &
operator()(std::pair<T1, T2> const & p) const
{
return p;
}

// unpack expression wrappers
template<typename T>
inline typename pair_result_traits<T>::type
operator()(const Daixt::Expr<T>& E) const
{
return (*this)(E.content());
}

// unary ops
template <typename ARG, typename OP>
inline typename pair_result_traits<Daixt::UnOp::type
operator()(const Daixt::UnOp<ARG, OP>& UO) const
{
typedef typename
pair_result_traits<Daixt::UnOp::type type;

typename pair_result_traits<ARG>::type tmp = (*this)(UO.arg());

return std::make_pair(
OP::Apply(tmp.first,
Daixt::Hint<typename
type::first_type>()),
OP::Apply(tmp.second,
Daixt::Hint<typename
type::second_type>())
);
}


// binary ops
template <typename LHS, typename RHS, typename OP>
inline typename pair_result_traits<Daixt::BinOp::type
operator()(const Daixt::BinOp<LHS, RHS, OP>& BO) const
{
typedef typename
pair_result_traits<Daixt::BinOp::type type;

typename pair_result_traits<LHS>::type lhs_tmp = (*this)(BO.lhs());
typename pair_result_traits<LHS>::type rhs_tmp = (*this)(BO.rhs());




return std::make_pair(
OP::Apply(lhs_tmp.first,
rhs_tmp.first,
Daixt::Hint<typename
type::first_type>()),
OP::Apply(lhs_tmp.second,
rhs_tmp.second,
Daixt::Hint<typename
type::second_type>())
);
}
};



// a std::caveat: "operator=" must be a member function (IMHO a wrong
// decision), so we have to take something else. I choose %=, but you may
// use an "Assign" function, too.

template <typename T1, typename T2, typename T>
std::pair<T1, T2> &
operator%=(std::pair<T1, T2> & p, Daixt::Expr<T> const & E)
{
p = My::Evaluator()(E);

return p;
}

} // namespace My



int main()
{

std::pair<float,int> p1(1.3,1);
std::pair<int,unsigned int> p2(2,2);

std::pair<double, double> test;

using Daixt::DefaultOps::operator+;
using Daixt::DefaultOps::operator-;
using My::operator%=;

test %= p1 + p2;

std::cerr << test.first << " " << test.second << std::endl;

std::cerr << My::Evaluator()(-p1 + p2 + p2).second << std::endl;
nop

typedef std::pair<_1, _2> type;
};


--

Build your own Expression Template Library with Daixtrose!
Visit http://daixtrose.sourceforge.net/

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

Back to top
Ulrich Eckhardt
Guest





PostPosted: Mon Sep 22, 2003 10:28 pm    Post subject: Re: std::pair<>::operator+ template deduction Reply with quote

Joshua Lehrer wrote:
Quote:
I was writing a program and I needed to be able to add two pairs
together. I was surprised to discover that std::pair has no operator+
defined. After sitting down and trying to write one, I believe I have
discovered why... it is really tough.

The problem lies in what would be the return value of the operator:

template <typename T1, typename T2, typename T3, typename T4
???? operator+(const std::pair &p2);

When adding pairs of like types, the return type is obvious. However,
when adding a pair should be pair<float,float>.

This reminds me of an article[1]: it is about a proper implementation of
std::max() and std::min() which suffers the same problem (and is really
good reading, thanks!).

hth

Ulrich Eckhardt

[1] http://www.cuj.com/documents/s=7996/cujcexp1904alexandr/



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

Back to top
Joshua Lehrer
Guest





PostPosted: Tue Sep 23, 2003 9:11 am    Post subject: Re: std::pair<>::operator+ template deduction Reply with quote

"Siemel Naran" <SiemelNaran (AT) REMOVE (DOT) att.net> wrote

Quote:
The same two objections apply.

(1) In X+Y, type of result is either X or Y. This may not always be the
case.

(2) X and Y have different sizeof. But they may be different types with the
same sizeof, as in X==signed int and Y==unsigned int.


I'm a bit lost. My solution does work even if X and Y have the same
sizeof(). Look back at my solution. I use 2 new types, basically, a
"YES" and a "NO", that have different sizes. I never take sizeof(X).

Yes, I agree with the problem that X+Y must return either X or Y.
This is certainly a limitation, but doesn't come up very frequently,
except....

const int + const int --> int.

I've been working my solution to take this into account. Also, I
found a workaround for my problem. My compiler doesn't like the
complex return value, as I posted. However, if I make the return
value simply the "result" typedef of a template, then it does work:

template <typename T1, typename T2, typename T3, typename T4>
inline typename PairPlus<T1,T2,T3,T4>::result
operator+(const std::pair<T1,T2> &p1, const std::pair<T3,T4> &p2) {
return PairPlus<T1,T2,T3,T4>(p1.first+p2.first,p1.second+p2.second);
}

it works just fine... even when PairPlus is implemented using all of
the same template tricks that I previously posted. Go figure.

So, given that I fix my CV qualifications issue, and I accept that
fact that A+B must return either an A or B (with any CV
qualifications), I think I have a workable solution, finally.

Oh, how much easier this would be with an auto or typeof:

template <typename T1, typename T2, typename T3, typename T4>
inline std::pair<typeof(T1()+T3()),typeof(T2()+T4()>
operator+(...);

Incidientally, using the default constructor, even at compile time, is
bad:

sizeof(func(T1()+T3());

because T1() or T3() may not have accessible default constructors. I
believe that this would be a compile time error, even though it isn't
really called. A better solution is to dereference a pointer:

sizeof(func((*((T1*)0))+(*((T3*)0))));

Unfortunately, this causes an error on my compiler about an illegal
reference to NULL. I have filed a bug with my vendor, as this is only
a compile-time idiom, and, therefore, not really a reference to NULL.
For the final code, I simply dereference 1 instead of 0.

joshua lehrer
factset research systems
NYSE:FDS

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

Back to top
Joshua Lehrer
Guest





PostPosted: Tue Sep 23, 2003 11:15 am    Post subject: Re: std::pair<>::operator+ template deduction Reply with quote

Ulrich Eckhardt <doomster (AT) knuut (DOT) de> wrote


Quote:
This reminds me of an article[1]: it is about a proper implementation of
std::max() and std::min() which suffers the same problem (and is really
good reading, thanks!).


yup, me too. That is where I got the idea from. In fact, given the
things I have learned from attempting to write this method, I believe
we can write a better min/max than that article had. That article
used typelists to list all of the types, and tried to hard-code rules
for which types convert to which, based on where they were in the
ordered typelist.

Using this technique, instead, you could use template meta-programming
to determine which types convert to which, and what the proper return
type should be.

Maybe someday I'll get a chance to work on that, after I finish my
pair operations.

joshua lehrer
factset research systems
NYSE:FDS

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

Back to top
Joel de Guzman
Guest





PostPosted: Wed Sep 24, 2003 11:39 am    Post subject: Limited typeof [ was Re: std::pair<>::operator+ template ded Reply with quote

"Joshua Lehrer" <usenet_cpp (AT) lehrerfamily (DOT) com> wrote in message

Quote:
Using this technique, instead, you could use template meta-programming
to determine which types convert to which, and what the proper return
type should be.

Maybe someday I'll get a chance to work on that, after I finish my
pair operations.

Actually there is such a limited-typeof facility already...

Jaakko Jarvi and I are working on the Boost Lambda Library
(http://www.boost.org/libs/lambda/doc/index.html) and Phoenix
merger ([url]http://www.boost.org/libs/spirit/phoenix/index.html)[/url].
Hopefully that will happen sometime in the near future. In an attempt
to do a better type deduction mechanism than what's provided in LL
(and Phoenix), I experimented with this idea:

(see [ http://tinyurl.com/ofqf ], requires Boost (and MPL))

In many cases, the result type of a binary expression is related to one of
its operands. The limited form of type deduction presented can detect
common relations if the result of a binary or unary operation, given arguments
x and y with types X and Y (respectively), is X, Y, X&, Y&, X*, Y*, X
const*, Y const*, bool, int, unsigned, double, container and iterator
elements (e.g the T, where X is: T[N], T*, vector<T>, map<T>,
vector<T>::iterator). More arguments/return type relationships can be
established if needed.

The (fully commented) code is just a prototype. The final version is slightly
different (some tweaks and bug-fixes here and there). Email me if you wish
to see the latest code.

Regards,
--
Joel de Guzman
http://www.boost-consulting.com
http://spirit.sf.net







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

Back to top
Hyman Rosen
Guest





PostPosted: Wed Sep 24, 2003 11:42 am    Post subject: Re: std::pair<>::operator+ template deduction Reply with quote

Reading this, a C++ extension occurrs to me, probably
not original. Wouldn't it be nice if we could do

export-opt template < template-parameter-list >
{
typedef-declaration-seq
class-and-function-declaration-seq
}

This would be equivalent to doing

export-opt template < template-parameter-list > declaration

for each member of the class-and-function-declaration-seq
with any typedefs defined in the typedef-declaration-seq
interpolated as their actual types.

The idea is to clarify the writing of templates, especially
function templates, which involve complicated expressions of
the template parameters. With the proposed syntax, the
complicated expressions could be built up as a sequence of
typedefs instead of having to be written as one expression.


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





PostPosted: Wed Sep 24, 2003 1:16 pm    Post subject: Re: std::pair<>::operator+ template deduction Reply with quote

"Joshua Lehrer" <usenet_cpp (AT) lehrerfamily (DOT) com> wrote in message
Quote:
"Siemel Naran" <SiemelNaran (AT) REMOVE (DOT) att.net> wrote


Quote:
The same two objections apply.

(1) In X+Y, type of result is either X or Y. This may not always be
the
case.

(2) X and Y have different sizeof. But they may be different types
with the
same sizeof, as in X==signed int and Y==unsigned int.


I'm a bit lost. My solution does work even if X and Y have the same
sizeof(). Look back at my solution. I use 2 new types, basically, a
"YES" and a "NO", that have different sizes. I never take sizeof(X).

OK, I worked it out. You're right.



Quote:
Yes, I agree with the problem that X+Y must return either X or Y.

I was thinking of something like this.

Float*Float = BigFloat.


Quote:
This is certainly a limitation, but doesn't come up very frequently,
except....

const int + const int --> int.

I've been working my solution to take this into account. Also, I

Consider this way

template <class T>
struct no_toplevel_const
{
typedef T result;
};

template <class T>
struct no_toplevel_const<const T>
{
typedef T result;
};

I'm not sure if the above is a valid specialization. One of my compilers
accepts it, but the other does not. If it doesn't compile on your compiler
try this trick which someone told me on this wonderful newsgroup

namespace helper
{
template <class T>
struct no_toplevel_const
{
typedef T result;
};

template <class T>
struct no_toplevel_const<T const *>
{
typedef T result;
};
}

template <class T>
struct no_toplevel_const
{
typedef typename helper::no_toplevel_const<T*>::result result;
};



Quote:
found a workaround for my problem. My compiler doesn't like the
complex return value, as I posted. However, if I make the return
value simply the "result" typedef of a template, then it does work:

template <typename T1, typename T2, typename T3, typename T4
inline typename PairPlus operator+(const std::pair<T1,T2> &p1, const std::pair<T3,T4> &p2) {
return PairPlus<T1,T2,T3,T4>(p1.first+p2.first,p1.second+p2.second);
}

it works just fine... even when PairPlus is implemented using all of
the same template tricks that I previously posted. Go figure.

What's funny is that all the compilers have this flaw.


Quote:
So, given that I fix my CV qualifications issue, and I accept that
fact that A+B must return either an A or B (with any CV
qualifications), I think I have a workable solution, finally.

Oh, how much easier this would be with an auto or typeof:

template <typename T1, typename T2, typename T3, typename T4
inline std::pair operator+(...);

Yes, it's a nice piece of code. You should post the final solution. But
they'll ask: if you can do it without typeof, then what need is there for a
new keyword?


Quote:
Incidientally, using the default constructor, even at compile time, is
bad:

sizeof(func(T1()+T3());

because T1() or T3() may not have accessible default constructors. I
believe that this would be a compile time error, even though it isn't
really called. A better solution is to dereference a pointer:

sizeof(func((*((T1*)0))+(*((T3*)0))));

Unfortunately, this causes an error on my compiler about an illegal
reference to NULL. I have filed a bug with my vendor, as this is only
a compile-time idiom, and, therefore, not really a reference to NULL.
For the final code, I simply dereference 1 instead of 0.

I think your compiler is right because sizeof(*(NULL)) contains an
expression *(NULL) which is undefined according to the standard. You're
asking the compiler to see how this expression is used, namely as the
argument of a sizeof expression, and conclude it is not undefined behavior
after all.

You can try this

template T getValue();

Quote:
sizeof(func((*((T1*)0))+(*((T3*)0))));

becomes

sizeof(func(getValue<T1>()+getValue<T3>()));

Would that work? I haven't compiled and tested it, but think it should
work.

Besides types we add together have an accessible default constructor anyway:
int, double, std::string.

--
+++++++++++
Siemel Naran


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

Back to top
Gabriel Dos Reis
Guest





PostPosted: Wed Sep 24, 2003 8:29 pm    Post subject: Re: std::pair<>::operator+ template deduction Reply with quote

Hyman Rosen <hyrosen (AT) mail (DOT) com> writes:

Quote:
Reading this, a C++ extension occurrs to me, probably
not original. Wouldn't it be nice if we could do

export-opt template < template-parameter-list
{
typedef-declaration-seq
class-and-function-declaration-seq
}

I would rather the region delimitated by the braces be a named scope.
Indeed, I too have been exploring the idea of parameterized namespaces
(and namespaces as template arguments). I have a couple of examples of
libraries that would benefit from that capability. I've yet to form that
idea precisely in my mind before writing anything formal as a proposal.

There are many constructs that could be written with namespaces
(e.g. using-directive, using-declaratiion at namespace or local scopes) and
constructs that could be written with classes (e.g. template
arguments) that would be even more useful if the could be combined
together.

Quote:
This would be equivalent to doing

export-opt template < template-parameter-list > declaration

for each member of the class-and-function-declaration-seq
with any typedefs defined in the typedef-declaration-seq
interpolated as their actual types.

The idea is to clarify the writing of templates, especially
function templates, which involve complicated expressions of
the template parameters. With the proposed syntax, the
complicated expressions could be built up as a sequence of
typedefs instead of having to be written as one expression.

the template alias proposal aims at solving (most of?) that issue.

--
Gabriel Dos Reis
[email]gdr (AT) integrable-solutions (DOT) net[/email]

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

Back to top
Joel de Guzman
Guest





PostPosted: Wed Sep 24, 2003 10:26 pm    Post subject: Re: Limited typeof [ was Re: std::pair<>::operator+ template Reply with quote

"Joel de Guzman" <djowel (AT) gmx (DOT) co.uk> wrote in message

Quote:
Jaakko Jarvi and I are working on the Boost Lambda Library
(http://www.boost.org/libs/lambda/doc/index.html) and Phoenix
merger ([url]http://www.boost.org/libs/spirit/phoenix/index.html)[/url].
Hopefully that will happen sometime in the near future. In an attempt
to do a better type deduction mechanism than what's provided in LL
(and Phoenix), I experimented with this idea:

(see [ http://tinyurl.com/ofqf ], requires Boost (and MPL))

In many cases, the result type of a binary expression is related to one of
its operands. The limited form of type deduction presented can detect
common relations if the result of a binary or unary operation, given arguments
x and y with types X and Y (respectively), is X, Y, X&, Y&, X*, Y*, X
const*, Y const*, bool, int, unsigned, double, container and iterator
elements (e.g the T, where X is: T[N], T*, vector<T>, map<T>,
vector<T>::iterator). More arguments/return type relationships can be
established if needed.

The (fully commented) code is just a prototype. The final version is slightly
different (some tweaks and bug-fixes here and there). Email me if you wish
to see the latest code.

Oh, I forgot to mention that, apart from Boost MPL, the code also
relies on enable_if, ( http://tinyurl.com/ohqj ). enable_if is already in boost's
review queue, you can find a copy in the boost sandbox
(http://sourceforge.net/projects/boost-sandbox)

Have fun,
--
Joel de Guzman
http://www.boost-consulting.com
http://spirit.sf.net




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

Back to top
Joshua Lehrer
Guest





PostPosted: Wed Sep 24, 2003 10:44 pm    Post subject: Re: Limited typeof [ was Re: std::pair<>::operator+ template Reply with quote

"Joel de Guzman" <djowel (AT) gmx (DOT) co.uk> wrote

Quote:
In many cases, the result type of a binary expression is related to one of
its operands. The limited form of type deduction presented can detect
common relations if the result of a binary or unary operation, given arguments
x and y with types X and Y (respectively), is X, Y, X&, Y&, X*, Y*, X
const*, Y const*, bool, int, unsigned, double, container and iterator
elements (e.g the T, where X is: T[N], T*, vector<T>, map<T>,
vector<T>::iterator). More arguments/return type relationships can be
established if needed.


Yeah, my final solution has support to do most of that as well. I
just didn't enumerate all of those types as you have. For now, I only
support X and Y, but I could easily add X&, Y&, X*, and Y* (anything
related to X and Y), as well as any standard types, like "bool".

For the time being, though, I don't have that need. I.e. if
operator+(X,Y) doesn't return either X or Y, it isn't going to return
"bool", it will probably return some proxy, which neither of our
systems can automatically catch.

joshua lehrer
factset research systems
NYSE:FDS

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

Back to top
Joshua Lehrer
Guest





PostPosted: Wed Sep 24, 2003 10:47 pm    Post subject: Re: std::pair<>::operator+ template deduction Reply with quote

"Siemel Naran" <SiemelNaran (AT) REMOVE (DOT) att.net> wrote


Quote:
Yes, I agree with the problem that X+Y must return either X or Y.

I was thinking of something like this.

Float*Float = BigFloat.


agreed, and my current system does not support that.

Quote:

This is certainly a limitation, but doesn't come up very frequently,
except....

const int + const int --> int.

I've been working my solution to take this into account. Also, I

Consider this way


Yes. I ended up using the boost trait, but it works the same way.

Quote:


What's funny is that all the compilers have this flaw.


well, I only tested EDG based compilers.

Quote:


Yes, it's a nice piece of code. You should post the final solution. But
they'll ask: if you can do it without typeof, then what need is there for a
new keyword?

Because I can't detect:

float*float --> bigfloat

without typeof

Quote:
You can try this

template <class T
T getValue();

sizeof(func((*((T1*)0))+(*((T3*)0))));

becomes

sizeof(func(getValue
Would that work? I haven't compiled and tested it, but think it should
work.


nice... I think I'll change to that.

Quote:
Besides types we add together have an accessible default constructor anyway:
int, double, std::string.

Well, usually, yes, but why place that requirement?

joshua lehrer
factset research systems
NYSE:FDS

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

Back to top
Hyman Rosen
Guest





PostPosted: Wed Sep 24, 2003 10:48 pm    Post subject: Re: std::pair<>::operator+ template deduction Reply with quote

Gabriel Dos Reis wrote:
Quote:
I would rather the region delimitated by the braces be a named scope.
Indeed, I too have been exploring the idea of parameterized namespaces
(and namespaces as template arguments).

You need to explore how that interacts with function template
argument deduction. My construct maps (I hope) to current C++,
and so should not interfere.


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

Back to top
Andrei Alexandrescu
Guest





PostPosted: Thu Sep 25, 2003 1:18 pm    Post subject: Re: std::pair<>::operator+ template deduction Reply with quote

"Joshua Lehrer" <usenet_cpp (AT) lehrerfamily (DOT) com> wrote

Quote:
Ulrich Eckhardt <doomster (AT) knuut (DOT) de> wrote


This reminds me of an article[1]: it is about a proper implementation
of
std::max() and std::min() which suffers the same problem (and is really
good reading, thanks!).


yup, me too. That is where I got the idea from. In fact, given the
things I have learned from attempting to write this method, I believe
we can write a better min/max than that article had. That article
used typelists to list all of the types, and tried to hard-code rules
for which types convert to which, based on where they were in the
ordered typelist.

Using this technique, instead, you could use template meta-programming
to determine which types convert to which, and what the proper return
type should be.

You can't. The rules for various types of numbers are hardcoded, there's
little deduction you can do. The conversion detectors can't tell whether
it's a conversion or a promotion.

Besides, min and max in particular have semantics that suggest further
heuristics. For example, min(unsigned char, unsigned int) will always return
unsigned char, and min(unsigned int, unsigned char) will always return
unsigned int and so on.


Andrei



[ 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
Goto page 1, 2  Next
Page 1 of 2

 
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.