(Templated) Operator overload on return type.

F

Fabio Fracassi

Hi,

I belive what i am trying to do is not possible, but I hope someone can
change my mind.

Here is some code i'd like to write:

template <class type> class engine1 {};
template <class type> class engine2 {};

template <template <class> class engine, class type>
class optest : public engine<type> {

public:
optest() : data() {}
optest(const optest& copy) : data(copy.data) {}

type data;
};

template <
template <class> class engine, // This isn't legal
template <class> class engine1,
template said:
const optest<engine, type> operator*(
const optest<engine1, type>& op1,
const optest<engine2, type>& op2) {
optest<engine, type> res;
res.data = op1.data * op2.data;
return res;
}

typedef optest<engine1, int> A1;
typedef optest<engine2, int> A2;

int main() {

A1 a1;
A2 a2;

// I'd like all of the operations below to work.

// These are easy ...
a1 = a1 * a1;
a2 = a2 * a2;

a1 = a1 * a2;
a2 = a2 * a1;

// ... but how can I do this
// without getting ambiguity errors, and ..
a1 = a2 * a1;
a2 = a1 * a2;

// ... how can I do this, at all?
a1 = a2 * a2;
a2 = a1 * a1;

return 0;
}

Is there a way, to do this without conversions. (Becuase these would be
expensive, in the real project).

TIA

Fabio
 
J

John Carson

Fabio Fracassi said:
Hi,

I belive what i am trying to do is not possible, but I hope someone
can change my mind.

The issue below isn't actually overloading; it is template argument
deduction. But, as with overloading, you can't do it on return type. There
is at least one alternative, however.
Here is some code i'd like to write:

template <class type> class engine1 {};
template <class type> class engine2 {};

template <template <class> class engine, class type>
class optest : public engine<type> {

public:
optest() : data() {}
optest(const optest& copy) : data(copy.data) {}

type data;
};

template <
template <class> class engine, // This isn't legal

It is legal. It is just that the compiler is unable to deduce engine from
the object to which you are assigning the result of the operator. This means
you have to specify it explicitly. See below.
template <class> class engine1,

const optest<engine, type> operator*(
const optest<engine1, type>& op1,
const optest<engine2, type>& op2) {
optest<engine, type> res;
res.data = op1.data * op2.data;
return res;
}

typedef optest<engine1, int> A1;
typedef optest<engine2, int> A2;

int main() {

A1 a1;
A2 a2;

// I'd like all of the operations below to work.

// These are easy ...
a1 = a1 * a1;
a2 = a2 * a2;

a1 = a1 * a2;
a2 = a2 * a1;

// ... but how can I do this
// without getting ambiguity errors, and ..
a1 = a2 * a1;
a2 = a1 * a2;

// ... how can I do this, at all?
a1 = a2 * a2;
a2 = a1 * a1;

return 0;
}

Is there a way, to do this without conversions. (Becuase these would
be expensive, in the real project).

The following compiles (you need the "illegal" line from above). It isn't as
nice to type, but you could use macros/inline functions to make it easier.

int main()
{

A1 a1;
A2 a2;

// I'd like all of the operations below to work.

// These are easy ...
a1 = operator*<engine1>(a1, a1);
a2 = operator*<engine2>(a2, a2);

a1 = operator*<engine1>(a1, a2);
a2 = operator*<engine2>(a2, a1);

// ... but how can I do this
// without getting ambiguity errors, and ..
a1 = operator*<engine1>(a2, a1);
a2 = operator*<engine2>(a1, a2);

// ... how can I do this, at all?
a1 = operator*<engine1>(a2, a2);
a2 = operator*<engine2>(a1, a1);

return 0;
}
 
F

Fabio Fracassi

The issue below isn't actually overloading; it is template argument
deduction. But, as with overloading, you can't do it on return type.

My mistake sorry.
It is legal. It is just that the compiler is unable to deduce engine from
the object to which you are assigning the result of the operator. This
means you have to specify it explicitly. See below.

Yes, of course. Sorry.
The following compiles (you need the "illegal" line from above). It isn't
as nice to type, but you could use macros/inline functions to make it
easier.

a1 = operator*<engine1>(a2, a1);

Yes, but this would somehow defy the purpose of operator overloading,
wouldn't it? I will have to check if expression templates could help here.

Thanks

Fabio
 
G

Greg

Fabio said:
Hi,

I belive what i am trying to do is not possible, but I hope someone can
change my mind.

Here is some code i'd like to write:

template <class type> class engine1 {};
template <class type> class engine2 {};

template <template <class> class engine, class type>
class optest : public engine<type> {

public:
optest() : data() {}
optest(const optest& copy) : data(copy.data) {}

type data;
};

template <
template <class> class engine, // This isn't legal
template <class> class engine1,

const optest<engine, type> operator*(
const optest<engine1, type>& op1,
const optest<engine2, type>& op2) {
optest<engine, type> res;
res.data = op1.data * op2.data;
return res;
}

These template parameter names used here are confusingly similar to the
class names also in use by the program. It might clarify matters to
declare the operator routine more distinctly:

template <
template <class> class E, // how to determine E?
template <class> class E1,
template said:
const optest<E, T>
operator*( const optest<E1, T>& op1,
const optest<E2, T>& op2 )
{
optest<E, type> res;

res.data = op1.data * op2.data;
return res;
}
typedef optest<engine1, int> A1;
typedef optest<engine2, int> A2;

int main() {

A1 a1;
A2 a2;

// I'd like all of the operations below to work.

// These are easy ...
a1 = a1 * a1;
a2 = a2 * a2;

a1 = a1 * a2;
a2 = a2 * a1;

// ... but how can I do this
// without getting ambiguity errors, and ..
a1 = a2 * a1;
a2 = a1 * a2;

// ... how can I do this, at all?
a1 = a2 * a2;
a2 = a1 * a1;

return 0;
}

Is there a way, to do this without conversions. (Becuase these would be
expensive, in the real project).

The first task to get this code to compile is to supply the missing
information. Namely, when mutliplying a type A1 object with a type A2
object, what is the type of the resulting product? Will it be of type
A1 or type A2 or some other type completely?

For the sake of discussion let's say the product's type is always the
same type as the lefthand operand:

template <
template <class> class E1,
template <class> class E2,
class T>
const optest<E1, T>
operator*( const optest<E1, T>& op1,
const optest<E2, T>& op2)
{
optest<E1, type> res;

res.data = op1.data * op2.data;
return res;
}

However the program also wants to be able to assign the product to a
variable of the righthand type:

a2 = a1 * a2;

To do so, optest needs to supply a template assignment operator (and
also a converting constructor, but I can't do all the work) in order
for the above statement to compile:

template <
template <class> class engine,
class type>
class optest : public engine<type>
{
public:
optest() : data() {}
optest(const optest& copy) : data(copy.data) {}

template <
template <class> class E, class T >
optest&
operator=( const optest<E, T>& op1 )
{
data = op1.data;
return *this;
}
type data;
};

Now, the sample code provided compiles correctly.

Greg
 
F

Fabio Fracassi

What I wrote above is important! In my real project the class in question
contain (sometimes big, i.e > 1mb) images, so ...
template <
template <class> class E, class T >
optest&
operator=( const optest<E, T>& op1 )
{
data = op1.data;

.... this extra copy of data is a real problem.
return *this;
}
type data;
};

As I already said in my reply to John, I will probably use some kind of
expression templates, which will also help when using more than one
operator in one expression.

Anyway thanks,

Fabio
 
G

Greg

Fabio said:
What I wrote above is important! In my real project the class in question
contain (sometimes big, i.e > 1mb) images, so ...


... this extra copy of data is a real problem.



As I already said in my reply to John, I will probably use some kind of
expression templates, which will also help when using more than one
operator in one expression.

You're barking up the wrong tree. Every one of your statements already
creates a copy of the data in a temporary variable and assigns it to
the left hand expression. Copying an A1 object into A2 object with a
programmer-supplied assignment operator is just as efficient (if not
more so) than any of the other copy expressions. The only difference
between:

a1 = a1 * a1;

and

a2 = a1 * a1;

is the that in the first the compiler writes the assignment operator
that copies the right hand expression into a1, while in the second the
programmer has to write the assignment operator to copy the same result
into a2. Otherwise there is no meaningful difference. So if the first
statement is reasonably efficient, then the second one using an
implementation-provided assignment operator, must be as well.

Furthermore if copy operations for these classes are so costly, then
none of the assignment statements in the sample code are reasonable.
But as a practical matter, large data structures should not be held by
value, but should be held indirectly, usually through a shared pointer
as a data member. The class holding the data should have well-thought
out copy semantics. A class whose copy semantics have been thought
through is one that either implements the proper constructor and
assignment operators for copyable types, or declares them private.
After all, data management is often too important to leave up to the
compiler-written routines (which are not even visible in the source
code) to handle.

Greg
 

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
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top