Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A converting constructor is a constructor that enables implicit type conversion from its parameter type(s) to the class type. It allows the compiler to automatically initialize an object of the class when a value of the parameter type is provided in a context expecting the class type. When the compiler encounters an expression of type T where an object of class C is expected, it searches for a converting constructor in C that accepts T. If found, the compiler generates a user-defined conversion sequence. Under C++17’s guaranteed copy elision (prvalue materialization rules), implicit conversions during copy-initialization (e.g., passing by value or returning by value) directly initialize the target object in place; the compiler does not create or destroy any intermediate temporary objects.

Syntax and Mechanics

A constructor functions as a converting constructor if it is not declared with the explicit specifier, or, starting in C++20, if it is declared with a conditionally explicit specifier that evaluates to false (explicit(false)). It is invoked during copy-initialization, pass-by-value function calls, and return-by-value statements.
class DataContainer {
public:
    int size;

    // Converting constructor (implicit by default)
    DataContainer(int s) : size(s) {} 
    
    // Converting constructor (C++20: explicit evaluates to false)
    explicit(false) DataContainer(const char* str) {} 
    
    // Converting constructor (multiple parameters with default arguments)
    DataContainer(double d, int padding = 0) {} 
};

void processContainer(DataContainer c) {}

int main() {
    // Copy-initialization: directly initializes c1 from int
    DataContainer c1 = 42; 

    // Function argument: directly initializes the parameter from int
    processContainer(100); 

    // Directly initializes c2 from const char*
    DataContainer c2 = "payload"; 
}

C++11 and Multi-Argument Converting Constructors

Prior to C++11, only constructors callable with exactly one argument were considered converting constructors. Starting with C++11, constructors requiring multiple arguments also function as converting constructors when utilized with brace-enclosed initializer lists (copy-list-initialization).
class Point {
public:
    int x, y;

    // Multi-argument converting constructor (C++11)
    Point(int x_val, int y_val) : x(x_val), y(y_val) {}
};

void drawPoint(Point p) {}

int main() {
    // Implicit conversion from initializer list to Point
    Point p1 = {10, 20}; 
    
    // Implicit conversion during function call
    drawPoint({5, 15});  
}

The explicit Specifier and C++20 explicit(bool)

To suppress implicit conversions, a constructor must be declared with the explicit keyword. An explicit constructor restricts object creation to direct-initialization, direct-list-initialization, or explicit type casting (e.g., static_cast). C++20 introduced conditionally explicit constructors (explicit(bool)), which evaluate a boolean constant expression at compile time. This allows a constructor to act as a converting constructor only if specific type traits are satisfied.
#include <type_traits>
#include <string>

template <typename T>
class StrictContainer {
public:
    // Non-converting constructor (unconditionally explicit)
    explicit StrictContainer(int) {}

    // C++20: Conditionally explicit constructor
    // Acts as a converting constructor ONLY if double is implicitly convertible to T
    explicit(!std::is_convertible_v<double, T>) StrictContainer(double) {}
};

int main() {
    // StrictContainer<std::string> c1 = 42; 
    // COMPILER ERROR: StrictContainer(int) is explicit and excluded from copy-initialization.
    // StrictContainer(double) evaluates to explicit(true) because double cannot convert to std::string.

    StrictContainer<std::string> c2(42);     
    // OK: direct-initialization explicitly invokes StrictContainer(int).

    StrictContainer<int> c3 = 42;            
    // OK: StrictContainer(int) is explicit and excluded. HOWEVER, double is convertible to int, 
    // so StrictContainer(double) evaluates to explicit(false) and acts as a converting constructor. 
    // The int `42` undergoes a standard conversion to double to satisfy this constructor.
}

Technical Constraints

  1. Single User-Defined Conversion: The C++ standard allows only one user-defined conversion sequence per implicit conversion. The compiler will not chain multiple converting constructors or combine a converting constructor with a user-defined conversion operator to resolve a type mismatch.
  2. Ambiguity and Standard Conversions: If multiple converting constructors can satisfy an implicit conversion via standard conversions of the same rank, the compiler will emit an ambiguous overload error. For example, passing an int to a class that has both a Constructor(double) and a Constructor(float) results in ambiguity. Both int to double and int to float are standard floating-integral conversions of equal rank. The compiler cannot determine a best viable function, unlike with standard promotions (e.g., short to int), which have a higher rank and are used to actively resolve overload ambiguities.
Master C++ with Deep Grasping Methodology!Learn More