porting expression templates to generics (2)

  • Thread starter Thread starter Zoran Stipanicev
  • Start date Start date
Z

Zoran Stipanicev

Hi!

I've changed the code to use Apply instead of operator() and now I get
this errors:
(1) left of '.Apply' must have class/struct/union
(2) left of '.GetRowNum' must have class/struct/union
(3) 'return' : cannot convert from
'Expression<Lhs,Rhs>' to 'Expression<Lhs,Rhs>'
Cannot copy construct struct 'Expression<Lhs,Rhs>' due to
ambiguous copy constructors or no available copy constructor


public interface class IExpression
{
public:
typedef System::Single tip;
virtual tip Apply(int r, int c);
virtual int GetRowNum();
};

generic <class Lhs, class Rhs>
where Lhs:IExpresion
where Rhs:IExpresion
ref struct Expression : public IExpresion
{
typedef float tip;
Expression( Lhs% lhs, Rhs% rhs)
: l_(lhs), r_(rhs)
{
}
virtual tip Apply (int r, int c)
{
(1) return l_.Apply(r, c) + r_.Apply(r, c);
}

virtual int GetRowNum()
{
(2) return l_.GetRowNum();
}

private:
Lhs l_;
Rhs r_;
}

generic <class Lhs, class Rhs>
where Lhs:IExpression
where Rhs:IExpression
Expression<Lhs, Rhs> operator +(Lhs% lhs, Rhs% rhs)
{
(3) return Expression<Lhs, Rhs>(lhs, rhs);
}
 
Zoran said:
generic <class Lhs, class Rhs>
where Lhs:IExpresion
where Rhs:IExpresion
ref struct Expression : public IExpresion
{
private:
Lhs l_;
Rhs r_;
}

Lhs and Rhs are of type IExpression, which are interface types, and
therefore they can't be instantiated. Try

private:
Lhs% l_;
Rhs% r_;

or use handles:

Expression(Lhs^ lhs, Rhs^ rhs) : l_(lhs), r_(rhs) { }
private:
Lhs^ l__;
Rhs^ r_;

Tom
 
Hi Tom!

I've tried that and the errors are:
error C3160: 'Rhs %' : a data member of a managed class cannot have
this type
error C3229: 'Rhs ^' : indirections on a generic type parameter are not
allowed

Any other idea?

Thx!

Best regards,
Zoran Stipanicev
 
I've tried that and the errors are:
error C3160: 'Rhs %' : a data member of a managed class cannot have
this type
error C3229: 'Rhs ^' : indirections on a generic type parameter are not
allowed

It seems that a generic parameter is a handle by itself, and you must
not use the ^ symbol with it. When you write

Lhs l_;

it's actually a handle, and works like if it was declared as

Lhs^ l_;

Therefore you can't use

l_.Assign

you must do

l_->Assign

I find this very confusing, it's a bad thing in my opinion. Declaring
something with stack semantics, which is in fact a handle? I wonder why
they made it like that. If it's a handle, it should have the caret
symbol, and if it's not a handle, it should use the . syntax, not ->. I
seem to be a serious inconsistency in the language.

Well, that covers errors 1 and 2. The 3rd is because you don't have a
copy constructor, and the compiler doesn't create one for you. You have
to write your own. I don't know if this does what you want, but it compiles:

Expression(Expression% source)
: l_(source.l_), r_(source.r_)
{
}

Tom
 
Thx!

I've rewritten the code and it solved those errors but now I get this
one:
stdafx.obj : error LNK2005: "struct DotNetMat::Expression<Lhs,Rhs>
__clrcall DotNetMat::operator+<Lhs,Rhs>(class MAAABAAB::Lhs
%,class MAAABAAC::Rhs %)
"
(??$?H$RLhs@MAAABAAB@$RRhs@MAAABAAC@@DotNetMat@@$$FYM?AU?$Expression@$RLhs@MAAABAAB@$RRhs@MAAABAAC@@0@A$CAVLhs@MAAABAAB@@A$CAVRhs@MAAABAAC@@@Z)
already defined in dotNET_Sustav_Matrica.obj
...\Debug\dotNET_Sustav_Matrica.exe : fatal error LNK1169:
one or more multiply defined symbols found

(DotNetMat in error text is a namespace in which
all classes and operators are defined)
I really don't know why this error occurs because there is only one
"operator +"
in whole project.

Here is the new code (I've added constructor and replaced "." with
"->"):


public interface class IExpression {/*same as before*/}

generic <class Lhs, class Rhs>
where Lhs:IExpression
where Rhs:IExpression
ref struct Expression : public DotNetMat::IExpression
{
typedef float tip;

Expression(Expression% org)
: l_(org.l_), r_(org.r_)
{
}

/*Also tried this but the same error occurs
Expression(const Expression% org)
: l_( const_cast<Lhs>(org.l_) ), r_(
const_cast<Rhs>(org.r_) )
{
}
*/
Expression( Lhs lhs, Rhs rhs)
: l_(lhs), r_(rhs)
{
}
virtual tip Apply (int r, int c)
{
return l_->Apply(r, c) + r_->Apply(r, c);
}

virtual int GetRowNum()
{
return l_->GetRowNum();
}
public:
Lhs l_;
Rhs r_;

};


generic <class Lhs, class Rhs>
where Lhs:IExpression
where Rhs:IExpression
Expression<Lhs, Rhs> operator +(Lhs% lhs, Rhs% rhs)//same error
with op+(Lhs lhs, Rhs rhs){...}
{
return Expression<Lhs, Rhs>(lhs, rhs);
}

main()
{
Matrix^ lhs = gcnew Matrix(3);//creates matrix 3x3
Matrix^ rhs = gcnew Matrix(3);

//...
System::Console::WriteLine( (lhs + rhs).Apply(1,1) ); //(lhs +
rhs)->Apply(1,1) can't be used

}


Best regards,
Zoran Stipanicev.
 
Hi!
About the syntax problem you mentioned, I found this in msdn library:

Handles types and value types may be used as type arguments. In the
generic
definition, in which either type may be used, the syntax is that of
reference
types. For example, the -> operator is used to access members of the
type of the
type parameter whether or not the type eventually used is a reference
type or a
value type. When a value type is used as the type argument, the runtime

generates code that uses the value types directly without boxing the
value
types.

When using a reference type as a generic type argument, use the handle
syntax.
When using a value type as a generic type argument, use the name of the
type
directly.

// generics_overview_2.cpp

// compile with: /clr

generic <typename T>

ref class GenericType {};


ref class ReferenceType {};

value struct ValueType {};


int main() {

GenericType<ReferenceType^> x;

GenericType<ValueType> y;
 
Back
Top