Skip to content

55 Intermediate The Hundred

The Constructor That Was a Conversion

a constructor with an open-door policy

#include <iostream>

struct Grid {
    int rows, cols;

    Grid(int r, int c) : rows(r), cols(c) {}
    Grid(int n) : rows(n), cols(n) {}   // square shortcut
};

void render(const Grid& g) {
    std::cout << "rendered a " << g.rows << "x" << g.cols << " grid\n";
}

int main() {
    Grid board(3, 4);
    render(board);
    render(5);   // left over from the old int-based render(int)
}

Run it. What does it print?

Answer

rendered a 3x4 grid, then rendered a 5x5 grid — the 5 became a grid nobody asked for.

Why

A constructor callable with one argument is not just a constructor: it is a standing offer to convert that argument type into your class, anywhere in the program. Overload resolution sees render(5), finds no render(int), spots Grid(int) and inserts one user-defined conversion — a temporary 5x5 Grid that lives just long enough for the call. The same open door makes Grid g = 5; legal and board = 9; too, so a typo can swap your 3x4 board for a 9x9 one. Nothing here troubles the compiler: -Wall -Wextra -Wconversion stays quiet. Since C++11 even multi-argument constructors convert from a braced list, so render({3, 4}) compiles too.

The fix

One keyword revokes the offer:

explicit Grid(int n) : rows(n), cols(n) {}

Now the stale call is a compile error instead of a wrong picture:

error: invalid initialization of reference of type ‘const Grid&’ from expression of type ‘int’
note:   in passing argument 1 of ‘void render(const Grid&)’

Deliberate construction still works — render(Grid{5}) prints rendered a 5x5 grid; you just have to ask out loud. Conversion operators deserve the same guard: an explicit operator bool() still works in if (h) but stops h + 1 from quietly compiling.

Takeaway: a one-argument constructor is a conversion offer to the whole program — say explicit unless you mean to make it.

Try it: g++ -std=c++17 main.cpp -o demo && ./demo — then add explicit to Grid(int).

Open in Compiler Explorer ↗ Quiz this entry