tags:

views:

2102

answers:

4

Several comments on a recent answer of mine, http://stackoverflow.com/questions/862858/what-other-useful-casts-can-be-used-in-c/862896#862896, suggest that my understanding of C++ conversions is faulty. Just to clarify the issue, consider the following code:

#include <string>

struct A {
    A( const std::string & s ) {}
};

void func( const A & a ) {
}

int main() {
    func( "one" );                  // error
    func( A("two") );         // ok
    func( std::string("three") );   // ok
}

My assertion was that the the first function call is an error, becauuse there is no conversion from a const char * to an A. There is a conversion from a string to an A, but using this would involve more than one conversion. My understanding is that this is not allowed, and this seems to be confirmed by g++ 4.4.0 & Comeau compilers. With Comeau, I get the following error:

"ComeauTest.c", line 11: error: no suitable constructor exists 
      to convert from "const char [4]" to "A"
      func( "one" );              // error

If you can point out, where I am wrong, either here or in the original answer, preferably with reference to the C++ Standard, please do so.

And the answer from the C++ standard seems to be:

At most one user-defined conversion (constructor or conversion function) is implicitly applied to a single value.

Thanks to Abhay for providing the quote.

+4  A: 

That's true, only one implicit conversion is allowed.

Two conversions in a row may be performed with a combination of a conversion operator and a parameterized constructor but this causes a C4927 warning - "illegal conversion; more than one user-defined conversion has been implicitly applied" - in VC++ for a reason.

sharptooth
+4  A: 

The C++ Programming Language (3rd. ed.) says (section 11.4.1) that

only one level of user-defined implicit conversion is legal

That "user-defined" part makes it sound like multiple implicit conversions may be allowed if some are between native types.

Max Lybbert
+1 for quoting form the latest ed. of Stroustrup's book
mloskot
+6  A: 

I think the answer from sharptooth is precise. The C++ Standard (SC22-N-4411.pdf) section 12.3.4 titled 'Conversions' makes it clear that only one implicit user-defined conversion is allowed.

1 Type conversions of class objects can be specified by constructors and by conversion functions. These conversions are called user-defined conversions and are used for implicit type conversions (Clause 4), for initialization (8.5), and for explicit type conversions (5.4, 5.2.9).

2 User-defined conversions are applied only where they are unambiguous (10.2, 12.3.2). Conversions obey the access control rules (Clause 11). Access control is applied after ambiguity resolution (3.4).

3 [ Note: See 13.3 for a discussion of the use of conversions in function calls as well as examples below. —end note ]

4 At most one user-defined conversion (constructor or conversion function) is implicitly applied to a single value.

Abhay
+3  A: 

As the consensus seems to be already: yes you're right.

But as this question / answers will probably become the point of reference for C++ implicit conversions on stackoverflow I'd like to add that for template arguments the rules are different.

No implicit conversions are allowed for arguments that are used for template argument deduction. This might seem pretty obvious but nevertheless can lead to subtle weirdness.

Case in point, std::string addition operators

 std::string s;
 s += 67;    // (1)
 s = s + 67; // (2)

(1) compiles and works fine, operator+= is a member function, the template character parameter is already deduced by instantiating std::string for s (to char). So implicit conversions are allowed (int -> char), results in s containing the char equivalent of 67, e.g. in ASCII this would become 'C'

(2) gives a compiler error as operator+ is declared as a free function and here the template character argument is used in deduction.

Pieter