[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
| Case | Without explicit | With explicit |
|---|---|---|
| Copy Initialization | String s = 10; ✅ | String s = 10; ❌ |
| Direct Initialization | String s(10); ✅ | String s(10); ✅ |
| Brace Initialization | String s{10}; ✅ | String s{10}; ✅ |
| Function Argument | func(10); ✅ | func(10); ❌ |
| Return Value | return 10; ✅ | return 10; ❌ |
| static_cast | static_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
| Feature | C++98 | C++11 | C++20 |
|---|---|---|---|
| Constructor | ✅ | ✅ | ✅ |
| Conversion Operator | ❌ | ✅ | ✅ |
| Conditional explicit | ❌ | ❌ | ✅ explicit(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:
| Scenario | Without explicit | With explicit |
|---|---|---|
process(10) | Creates String(10) and passes it | Compile Error |
String s = 10 | Creates String(10) | Compile Error |
String s(10) | Creates String(10) | Creates String(10) |
return 10 | Returns 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:
| Context | explicit bool | Description |
|---|---|---|
if (obj) | ✅ Allowed | Conditional statements |
while (obj) | ✅ Allowed | Loop conditions |
obj && x | ✅ Allowed | Logical operators |
!obj | ✅ Allowed | Logical NOT |
bool b = obj | ❌ Error | Copy initialization not allowed |
int x = obj | ❌ Error | Integer 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
| Scenario | Use explicit | Reason |
|---|---|---|
Vector(size_t size) | ✅ Required | Prevent unintended size conversions |
String(const char*) | ❌ Optional | String literal conversion is natural |
operator bool() | ✅ Required | Prevent unintended integer conversions |
operator int() | ✅ Recommended | Prevent unintended arithmetic operations |
Widget(int, int) | ❌ Not Needed | Multi-argument constructors don’t allow implicit conversions |
unique_ptr(T* ptr) | ✅ Required | Prevent 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:
- “Effective C++”
- “C++ Primer”
- cppreference.com Related Posts: Type Conversion, Copy Initialization, Smart Pointers.
## 같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- [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** 등으로 검색하시면 이 글이 도움이 됩니다.