P45 Imminent
P45 Imminent

Reputation: 8591

How explicit must you be when calling a constructor?

I have this class

struct foo
{
    explicit foo(const std::uint32_t& x, const std::uint32_t& y);
};

and a method

int main()
{
    std::int32_t x = -1;
    std::int32_t y = -1;
    foo f(x, y);
}

On my compiler (MSVC2012), this compiles and runs with the values x and y wrapped around to unsigned types. I was not expecting this, but was expecting a compile error due to mismatched types.

What am I missing?

Upvotes: 12

Views: 355

Answers (3)

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385174

explicit does not prevent implicit conversion with the constructor arguments (which clearly takes place here when binding the references); it prevents implicit construction.

void bar(foo);
int main()
{
   foo f({0, 0}); // doesn't matter that the arguments are implicitly converted

   bar({0, 0});   // error - implicit conversion required here to pass a foo
   bar(f);        // crucially, ok because argument requires no conv. construction
}

Upvotes: 0

HiroshimaCC
HiroshimaCC

Reputation: 486

Actually, you should use the new brace-initialization syntax foo f{x, y} that will at least emit a warning. After that you can configure your compiler to treat warnings as errors and handle them accordingly, as good code should usually get rid of warnings too (because if you wanted the conversion to happen, you should have used an explicit cast).

Upvotes: 0

Bathsheba
Bathsheba

Reputation: 234715

You're out of luck, the standard does allow implicit conversion of signed to unsigned via the creation of an anonymous temporary for an argument passed by constant reference.

(Note this is not true for a non-constant reference).

If you're using C++11, the best thing to do is to delete the constructor using

foo(const std::int32_t& x, const std::int32_t& y) = delete;

Pre C++11 you could make this constructor private and not define it. Rather like the old-fashioned not-copyable idioms.

MSVC2012 is a sort of half-way house C++03 / C++11 compiler. It implements some C++11 features but not others. Unfortunately deletion of constructors is one of the features it does not support so the privateisation approach is the best method available to you.

Upvotes: 8

Related Questions