[2026] C++ explicit Keyword | explicit Keyword Guide

[2026] C++ explicit Keyword | explicit Keyword Guide

이 글의 핵심

C++ explicit. Preventing implicit conversions, constructors, and conversion operators.

originalId: cpp-explicit-keyword

What is explicit?

The explicit keyword is used with constructors and conversion operators to prevent implicit conversions. It is particularly useful for avoiding unintended conversions during copy initialization with = expr. Most constructors for smart pointers are also explicit for this reason.

Comparison: With and Without explicit

CaseWithout explicitWith explicit
Copy InitializationString s = 10;String s = 10;
Direct InitializationString s(10);String s(10);
Brace InitializationString s{10};String s{10};
Function Argumentfunc(10);func(10);
Return Valuereturn 10;return 10;
static_caststatic_cast<String>(10)static_cast<String>(10)
class String {
public:
    String(int size) {}  // Allows implicit conversion
};
String s = 10;  // OK: int -> String
// Using explicit
class String {
public:
    explicit String(int size) {}
};
// String s = 10;  // Error
String s(10);  // OK: Explicit initialization

Conversion Process Diagram

graph LR
    A[int value] -->|Without explicit| B[Implicit Conversion]
    B --> C[Constructor Call]
    C --> D[Object Creation]
    
    A -->|With explicit| E{Initialization Method}
    E -->|Copy Initialization =| F[Compile Error]
    E -->|Direct Initialization| G[Constructor Call]
    G --> D

Using explicit with Constructors

Problem Scenario

graph TD
    A[Function Call: process 10] --> B{Constructor explicit?}
    B -->|No| C[Allows Implicit Conversion]
    C --> D[Temporary Array 10 Object Created]
    D --> E[Function Execution]
    E --> F[Unintended Behavior]
    
    B -->|Yes| G[Compile Error]
    G --> H[Explicit Conversion Required]
    H --> I[process Array 10]
    I --> J[Clear Intent]
class Array {
public:
    // ❌ Allows implicit conversion
    Array(int size) {}
};
void process(Array arr) {}
int main() {
    process(10);  // int -> Array (unintended)
}
// ✅ Using explicit
class Array {
public:
    explicit Array(int size) {}
};
// process(10);  // Error
process(Array(10));  // OK

Practical Examples

Example 1: Basic Usage

class Vector {
    double* data;
    size_t size;
    
public:
    explicit Vector(size_t s) : size(s) {
        data = new double[size];
    }
    
    ~Vector() {
        delete[] data;
    }
};
void process(Vector v) {}
int main() {
    // process(10);  // Error
    process(Vector(10));  // OK
}

Example 2: Conversion Operator

class Fraction {
    int numerator, denominator;
    
public:
    Fraction(int n, int d) : numerator(n), denominator(d) {}
    
    // ❌ Implicit Conversion
    operator double() const {
        return (double)numerator / denominator;
    }
};
Fraction f(1, 2);
double d = f;  // Implicit conversion
// ✅ Explicit Conversion Operator
class Fraction {
public:
    explicit operator double() const {
        return (double)numerator / denominator;
    }
};
// double d = f;  // Error
double d = static_cast<double>(f);  // OK

Conversion Operator Workflow:

sequenceDiagram
    participant Code
    participant Compiler
    participant Op as Operator
    
    Code->>Compiler: double d = f;
    
    alt no explicit
        Compiler->>Op: implicit call
        Op->>Code: return double
        Note over Code: OK
    else with explicit
        Compiler->>Compiler: block implicit
        Compiler->>Code: compile error
    end
    
    Code->>Compiler: static_cast
    Compiler->>Op: explicit call
    Op->>Code: return double
    Note over Code: always OK

Example 3: bool Conversion

class SmartPointer {
    int* ptr;
    
public:
    explicit SmartPointer(int* p) : ptr(p) {}
    
    // ✅ Explicit bool
    explicit operator bool() const {
        return ptr != nullptr;
    }
};
int main() {
    SmartPointer sp(new int(10));
    
    if (sp) {  // OK: Allowed in conditional statements
        std::cout << "Valid" << std::endl;
    }
    
    // bool b = sp;  // Error
    bool b = static_cast<bool>(sp);  // OK
}

Example 4: Copy Constructor

class Widget {
public:
    Widget() = default;
    
    // Explicit Copy Constructor (Rare)
    explicit Widget(const Widget& other) {
        // ...
    }
};
Widget w1;
// Widget w2 = w1;  // Error
Widget w2(w1);  // OK

C++11 explicit Extensions

explicit Support by C++ Version

FeatureC++98C++11C++20
Constructor
Conversion Operator
Conditional explicitexplicit(bool)
Multi-Argument Constructor✅ (Brace Initialization)
// C++11: explicit for Conversion Operators
class MyClass {
public:
    explicit operator int() const {
        return 42;
    }
};
MyClass obj;
// int x = obj;  // Error
int x = static_cast<int>(obj);  // OK

C++20 Conditional explicit

template<typename T>
class Optional {
public:
    // Conditional explicit
    template<typename U>
    explicit(!std::is_convertible_v<U, T>)
    Optional(U&& value) : data(std::forward<U>(value)) {}
    
private:
    T data;
};
// int -> long is convertible → Not explicit
Optional<long> opt1 = 10;  // OK
// string -> int is not convertible → explicit
// Optional<int> opt2 = std::string("10");  // Error

Common Issues

Issue 1: Unintended Conversion

graph LR
    A[process 10 Call] --> B{String int Constructor}
    B -->|Without explicit| C[int → String Implicit Conversion]
    C --> D[Temporary String 10 Created]
    D --> E[Function Execution]
    E --> F[⚠️ Potential Bug]
    
    B -->|With explicit| G[❌ Compile Error]
    G --> H[Developer Expresses Intent Clearly]
    H --> I[process String 10]
    I --> J[✅ Safe Code]
// ❌ Without explicit
class String {
public:
    String(int size) {}
};
void process(String s) {}
process(10);  // Unintended conversion
// ✅ With explicit
class String {
public:
    explicit String(int size) {}
};

Real-World Examples:

ScenarioWithout explicitWith explicit
process(10)Creates String(10) and passes itCompile Error
String s = 10Creates String(10)Compile Error
String s(10)Creates String(10)Creates String(10)
return 10Returns String(10)Compile Error

Issue 2: Copy Initialization

class Widget {
public:
    explicit Widget(int x) {}
};
// Widget w = 10;  // Error
Widget w(10);  // OK
Widget w{10};  // OK (C++11)

Issue 3: Function Arguments

void func(std::vector<int> vec) {}
// ❌ Without explicit
// func(10);  // int -> vector (unintended)
// std::vector constructor is explicit
func(std::vector<int>(10));  // OK

Issue 4: bool Conversion

class Pointer {
public:
    operator bool() const {  // Without explicit
        return ptr != nullptr;
    }
    
private:
    int* ptr;
};
Pointer p;
int x = p;  // Converts to bool, then to int (unintended)
// ✅ With explicit
explicit operator bool() const {}

bool Conversion Issue Diagram:

graph TD
    A[Pointer p] --> B{operator bool explicit?}
    
    B -->|No| C[int x = p]
    C --> D[Pointer → bool]
    D --> E[bool → int]
    E --> F[⚠️ x = 0 or 1]
    F --> G[Unintended Integer Conversion]
    
    B -->|Yes| H[int x = p]
    H --> I[❌ Compile Error]
    I --> J[if p is OK]
    I --> K[Explicit Cast Required]

Allowed bool Conversion Contexts:

Contextexplicit boolDescription
if (obj)✅ AllowedConditional statements
while (obj)✅ AllowedLoop conditions
obj && x✅ AllowedLogical operators
!obj✅ AllowedLogical NOT
bool b = obj❌ ErrorCopy initialization not allowed
int x = obj❌ ErrorInteger conversion not allowed

Recommendations for explicit Usage

explicit Decision Flow

graph TD
    A[Writing Constructor/Conversion Operator] --> B{Single-Argument Constructor?}
    B -->|Yes| C{Intended Implicit Conversion?}
    B -->|No| D{Conversion Operator?}
    
    C -->|No| E[Use explicit ✅]
    C -->|Yes| F[Can Omit explicit]
    
    D -->|Yes| G{bool Conversion?}
    D -->|No| H[explicit Not Needed]
    
    G -->|Yes| E
    G -->|No| C

Code Guidelines

// ✅ Recommended explicit Usage
// 1. Single-Argument Constructor
explicit MyClass(int x);
// 2. Conversion Operator
explicit operator int() const;
// 3. bool Conversion Operator (Mandatory)
explicit operator bool() const;
// ❌ explicit Not Needed
// 1. Multi-Argument Constructor
MyClass(int x, int y);  // No implicit conversion
// 2. Copy/Move Constructor
MyClass(const MyClass&);  // Rarely explicit
// 3. Default Constructor
MyClass();  // No arguments

Practical Checklist

ScenarioUse explicitReason
Vector(size_t size)✅ RequiredPrevent unintended size conversions
String(const char*)❌ OptionalString literal conversion is natural
operator bool()✅ RequiredPrevent unintended integer conversions
operator int()✅ RecommendedPrevent unintended arithmetic operations
Widget(int, int)❌ Not NeededMulti-argument constructors don’t allow implicit conversions
unique_ptr(T* ptr)✅ RequiredPrevent automatic pointer conversions

FAQ

Q1: When should I use explicit?

A:

  • Single-argument constructors
  • Conversion operators
  • To prevent unintended conversions

Q2: Does explicit affect performance?

A: No. It is a compile-time check.

Q3: What about copy constructors?

A: Rarely explicit. Only in special cases.

Q4: What changed in C++11?

A: explicit can now be used with conversion operators.

Q5: What about bool conversions?

A: explicit is recommended to prevent unintended conversions.

Q6: Where can I learn more about explicit?

A:

## 같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- [C++ 타입 변환 | "Type Conversion" 가이드](/blog/cpp-type-conversion/)
- [C++ Copy Initialization | "복사 초기화" 가이드](/blog/cpp-copy-initialization/)
- [C++ 복사/이동 생성자 | "Rule of Five" 가이드](/blog/cpp-copy-move-constructor/)
- [C++ 스마트 포인터 | unique_ptr/shared_ptr "메모리 안전" 가이드](/blog/cpp-smart-pointers/)
---
---
## 이 글에서 다루는 키워드 (관련 검색어)
**C++**, **explicit**, **conversion**, **constructor**, **C++11** 등으로 검색하시면 이 글이 도움이 됩니다.
... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3