Constructors we should not make explicit

  1. We should not make copy (and move) constructors explicit as they do not perform conversions.
  2. Default constructors with no parameters as we usually use them for implicit conversion of {}.
  3. Constructors with multiple arguments as usually they are not candidates for conversions.

If we prefer, we can make option 2 and 3 as explicit.

Constructors we should make explicit

We should make single argument constructors explicit. However, there are cases when it is useful to have single-argument constructors non-explicit:

  1. When the conversion is not expensive such as for fundamental types as arguments.
  2. When the argument value is semantically equivalent to the constructed object.

Consider the example provided in this note, Int(int) can be made non-explicit as printInt(5) and printInt(Int) are semantically equivalent and conversion is inexpensive.

Now, consider the following program:

void printString(std::string s)
{
    std::cout << s << "\n";
}
 
printString("hello world"sv); // throws error

std::string constructor taking string view as argument is explicit and so the program fails. Although string view and std::string are semantically equivalent but conversion from string view to std::string is expensive.

On the other hand, std::string_view constructor taking std::string is non-explicit as they are semantically equivalent and conversion is inexpensive. For example,

void printString(std::string_view sv)
{
    std::cout << sv << "\n";
}
 
printString("hello world"s);

References

  1. https://www.learncpp.com/cpp-tutorial/converting-constructors-and-the-explicit-keyword/