Show: Object Pascal C++
Display Preferences

Stricter C++ Compiler - Initialization and Conversion

From Appmethod Topics
Jump to: navigation, search

Go Up to Stricter C++ Compiler (Appmethod C++) Index

The compiler now obeys the rules of 8.5.1 and 13.3.1 of the 2003 C++ ANSI Standard for initialization and conversion:

  • Direct initialization now requires initialization by a constructor and no longer picks a user conversion sequence.
  • Copy initialization for objects of the same or derived type now requires a constructor call.
  • Copy initialization for objects of the different types no longer prefers user conversion over construction. If the compiler finds a suitable user conversion, it now continues to look for (possibly ambiguous) converting constructors. If the chosen conversion function is a converting constructor, the call initializes a temporary of the destination type. The result of the call (which is the temporary for the constructor case) is then used to directinitialize the object. Use the compiler switch -Vbo to revert to the previous behavior.
  • For an explicit cast, the compiler now performs direct initialization on a temporary.

This example illustrates the new behavior:

// In this example, dst is destination type and src is source type   
   class A { };  
   class V {    public:      V() { };      
     V( const V & ) { }     
     V( const A & ) { }    
     };
   G g;    
   V v;
  // direct initialization
  // ==> constructors are considered.
  V v9(g);
  // Both of these statements previously compiled but now get the error:
  // Error E2015 Ambiguity between 'V::V(const V &)' and 'V::V(const A &)'

  // casts
  // (V)g is treated as V tmp(g) which is direct initialization of 'tmp'
  // ==> constructors are considered.
  (V)g;
  static_cast<V> (g);
  // Both of these statements previously compiled but now get the error:
  // Error E2015 Ambiguity between 'V::V(const V &)' and 'V::V(const A &)'

  // copy initialization with dst=V src=G
  // ==> user-defined conversion sequences are considered.
  V v4 = g;
  V v5 = G();
  // Both of these statements now compile but previously got the error:
  // Error E2015 Ambiguity between 'V::V(const A &)' and 'V::V(const V &)'

  // copy initialization with dst=V src=V
  // ==> converting constructors of V are considered.
  V v6 = (V)g;
  V v7 = V(g);
  // Both of these statements compiled previously but now get the error:
  // Error E2015 Ambiguity between 'V::V(const V &)' and 'V::V(const A &)'

Conversion via User-Defined Operators

The new Appmethod C++ 2007 compiler often reports ambiguities for conversions that involve user-defined operators. An example is shown below:

class AnsiString   
{   
   public:   
     bool operator ==(const AnsiString&    
     other);   
     AnsiString(const wchar_t* src);   
};
class Variant   
{   
  public:       
  operator AnsiString() const;
  operator wchar_t*() const;     
  bool operator ==(const AnsiString& rhs) const     
  { return static_cast<AnsiString>(*this) == rhs;}

Appmethod C++ users might notice that the above is a stripped down version of the VCL AnsiString and Variant classes. Previous versions of the compiler invoked the 'Variant' 'operator AnsiString() const' for 'static_cast<AnsiString>(*this)', while Appmethod C++ 2007 uses 'conversion via constructor'. Since the Variant can be converted to multiple types for which there are AnsiString constructors, the compiler generates an ambiguity error.

To correct this ambiguity error, you must eliminate the cast as in:

 bool operator ==(const AnsiString& rhs) const
  { return (*this) == rhs;}

You can also be explicit about the operator:

bool operator ==(const AnsiString& rhs) const
  { return this->operator AnsiString() == rhs; }

Variant/OleVariant/AnsiString/WideString/TDateTime

The issue described above with a user-defined conversion operator vs. conversion via constructor might be encountered in several constructs involving the VCL classes Variant, OleVariant, AnsiString, WideString, TDateTime, Currency, and so forth.

The following table lists constructs that now generate error messages and the updated syntax.

Previous Construct Updated Construct Notes
AnsiString test(OleVariant v) {
  AnsiString ret = (AnsiString) v;
  return ret;
}
AnsiString test(OleVariant v) {
  AnsiString ret = /*(AnsiString)*/ v;
  return ret;
}

Do not cast RHS when relying on conversion operator in an assignment.

WideString test(OleVariant v) {
  WideString w(v);
  return w;
}
WideString test(OleVariant v) {
  WideString w = v;
  return w;
}

Use Copy Initialization instead of the more direct constructor.



The underlying compiler change for the errors described above is related to the way the compiler now handles initialization and conversion.

See Also

Personal tools
In other languages