This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Possible problem with template selection


I have a C++ code snippet that I think is standard compliant, but does not
compile with g++ (v2.95.2 or v2.96 20000410).  This does compile and run with
KCC (3.4d and 3.4g), IBM's xlc, and Dec's cxx.

Here is a summary of the problem.  I have a templated container class Field,
which is templated on the element data type.  We would like to define some
operator* operations for this Field, so that we can use it in arithmetic
multiplication operations.  However, we might want to multiply Fields of
different element types (such as Field<Vector3d>*Field<double> =
Field<Vector3d>), so we have to make the operator* a templated function as
well.  We also might want to multiply Fields by single data types, where every
element in the Field gets multiplied by this single value.  So we would
envision three template definitions for operator*:

1.  template<DataType1, DataType2> 
    operator*(Field<DataType1>&, Field<DataType2>&)

2.  template<DataType1, DataType2> 
    operator*(DataType1&, Field<DataType2>&)

3.  template<DataType1, DataType2> 
    operator*(Field<DataType1>&, DataType2&)

If I try to compile this with g++, when g++ tries to resolve Field*Field
operations it appears to become confused by the second and third definitions,
and selects one of those instead of method 1.  I *think* this is incorrect
behaviour, since the compiler should pick the most specific possible version of
a function, which for Field*Field multiplication should be option 1.

Here's the error message reported by g++ v2.95.2:

TemplateOverload.cc: In function `int main()':
TemplateOverload.cc:102: no type named `ProductType' in `struct CombineTypes<Field<A>,B>'
TemplateOverload.cc:102: template argument 1 is invalid
TemplateOverload.cc:102: `operator *<Field<A>, B>(...)' must have an argument of class or enumerated type
TemplateOverload.cc:102: `operator *<Field<A>, B>(...)' must take either one or two arguments
TemplateOverload.cc:94: no type named `ProductType' in `struct CombineTypes<A,Field<B> >'
TemplateOverload.cc:94: template argument 1 is invalid
TemplateOverload.cc:94: `operator *<A, Field<B> >(...)' must have an argument of class or enumerated type
TemplateOverload.cc:94: `operator *<A, Field<B> >(...)' must take either one or two arguments

And here's the complete code:

#include<iostream>
using namespace std;

//------------------------------------------------------------------------------
class A {
public:
   A() {
      cout << "A::A()" << endl;
   }
   ~A() {
      cout << "A::~A()" << endl;
   }

   A& operator=(const A&) {
      cout << "A::operator=()" << endl;
      return *this;
   }
};

//------------------------------------------------------------------------------
class B {
public:
   B() {
      cout << "B::B()" << endl;
   }
   ~B() {
      cout << "B::~B()" << endl;
   }

   B& operator=(const B&) {
      cout << "B::operator=()" << endl;
      return *this;
   }
};

//------------------------------------------------------------------------------
A
operator*(const A& Ainstance,
          const B& Binstance) {
   cout << "operator*(A,B)" << endl;
   return A();
}

A
operator*(const B& Binstance,
          const A& Ainstance) {
   cout << "operator*(B,A)" << endl;
   return A();
}

//------------------------------------------------------------------------------
template<typename DataType1, typename DataType2>
struct CombineTypes {};

template<>
struct CombineTypes<A, B> {
   typedef A ProductType;
};

template<>
struct CombineTypes<B, A> {
   typedef A ProductType;
};

//------------------------------------------------------------------------------
template<typename DataType>
class Field {
public:
   Field() {
      cout << "Field::Field()" << endl;
   }
   ~Field() {
      cout << "Field::~Field()" << endl;
   }

   Field& operator=(const Field&) {
      cout << "Field::operator=()" << endl;
      return *this;
   }
};

//------------------------------------------------------------------------------
template<typename DataType1, typename DataType2>
Field<typename CombineTypes<DataType1, DataType2>::ProductType>
operator*(const Field<DataType1>& lhs,
          const Field<DataType2>& rhs) {
   cout << "operator*(Field, Field)" << endl;
   return Field<typename CombineTypes<DataType1, DataType2>::ProductType>();
}

template<typename DataType1, typename DataType2>
Field<typename CombineTypes<DataType1, DataType2>::ProductType>
operator*(const Field<DataType1>& lhs,
          DataType2& rhs) {
   cout << "operator*(Field, DataType)" << endl;
   return Field<typename CombineTypes<DataType1, DataType2>::ProductType>();
}

template<typename DataType1, typename DataType2>
Field<typename CombineTypes<DataType1, DataType2>::ProductType>
operator*(DataType1& lhs,
          const Field<DataType2>& rhs) {
   cout << "operator*(DataType, Field)" << endl;
   return Field<typename CombineTypes<DataType1, DataType2>::ProductType>();
}

//------------------------------------------------------------------------------
int main() {

   A Ainstance;
   B Binstance;

   Field<A> Afield;
   Field<B> Bfield;

   cout << "----------------------------------------" << endl;
   cout << "main: A*B" << endl;
   A Ainstance2 = Ainstance*Binstance;

   cout << "----------------------------------------" << endl;
   cout << "main: Afield*Bfield" << endl;
   Field<A> Afield2 = Afield*Bfield;

   cout << "----------------------------------------" << endl;
   cout << "main: A*Bfield" << endl;
   Field<A> Afield3 = Ainstance*Bfield;

   cout << "----------------------------------------" << endl;
   cout << "main: Bfield*A" << endl;
   Field<A> Afield4 = Bfield*Ainstance;

   cout << "----------------------------------------" << endl;
   cout << "main: B*Afield" << endl;
   Field<A> Afield5 = Binstance*Afield;

   cout << "----------------------------------------" << endl;
   cout << "main: Afield*B" << endl;
   Field<A> Afield6 = Afield*Binstance;

   return 0;
}


--
 "Hey...where are the sunflower seeds?" |       J. Michael Owen         
        o_o /                           |       
        (")                             |       Email:  mikeowen@llnl.gov
       \/'\/                            |
____(__(,_,)_______________________________________________________________

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]