tags:

views:

228

answers:

2

I'm changing an old routine that used to take an integer parameter so that it now takes a const reference to an object. I was hoping that the compiler would tell me where the function is called from (because the parameter type is wrong), but the object has a constructor that takes an integer, so rather than failing, the compiler creates a temporary object, passing it the integer, and passes a reference to that to the routine. Sample code:

class thing {
  public:
    thing( int x ) {
        printf( "Creating a thing(%d)\n", x );
    }
};

class X {
  public:
    X( const thing &t ) {
        printf( "Creating an X from a thing\n" );
    }
};


int main( int, char ** ) {
    thing a_thing( 5 );
    X an_x( 6 );
    return 1;
}

I want the X an_x( 6 ) line to not compile, because there is no X constructor that takes an int. But it does compile, and the output looks like:

Creating a thing(5)
Creating a thing(6)
Creating an X from a thing

How can I keep the thing( int ) constructor, but disallow the temporary object?

+11  A: 

Use the explicit keyword in the thing constructor.

class thing {
public:
    explicit thing( int x ) {
        printf( "Creating a thing(%d)\n", x );
    }
};

This will prevent the compiler from implicitly calling the thing constructor when it finds an integer.

Paolo Tedesco
See this answer: http://stackoverflow.com/questions/121162/what-does-the-explicit-keyword-in-c-mean
Skizz
Perfect - I have been writing C++ code for about 15 years, and have never heard of the explicit keyword. Thanks!
Graeme Perrow
Related question - can you use the explicit keyword on a method that's not a constructor?
Graeme Perrow
No, explicit is only for constructors. You can't stop implicit conversions for parameters in other methods.
Mark Ransom
+1  A: 

The explicit keyword works perfectly in my example, but I realized later that my real world code was failing on an overloaded method, not the constructor. (My fault for asking a question that was similar to, but not the same as, my actual problem.) As Mark Ransom pointed out in the comments on the accepted answer, explicit only works on constructors. I came up with a workaround that solved my problem, so I figured I'd post it here. New sample code:

class thing {
  public:
    thing( int x ) {
        printf( "Creating a thing(%d)\n", x );
    }
};

class X {
  public:
    void do_something( const thing &t ) {
        printf( "Creating an X from a thing\n" );
    }
};


int main( int, char ** ) {
    thing a_thing( 5 );
    X an_x;
    an_x.do_something( 6 );
    return 1;
}

This code shows the same output as the original code, but I can't use explicit to fix it. Instead, I added a private method that takes an int:

  private:
    void do_something( int x );

Now, the compiler doesn't create the temporary object, it gives an error because I am trying to call a private method from outside the class.

Graeme Perrow
in c++1x, we will be able to write void do_something( int x ) = delete; already works in gcc svn trunk.
Johannes Schaub - litb
@Graeme Perrow. Explicit should still work in the case you outline. That is, making the thing constructor explicit will result in a compiler error. Is it because you don't have access to the thing class to modify it?@litb have we started calling it C++1x now? Did I miss the memo?
zdan
@zdan: you're right. I was thinking about how to modify the X class and wasn't thinking about modifying the thing class. That does what I need. Thanks!
Graeme Perrow