C++11coreintermediate
Explicit Conversion Operators (C++11 Addition)
C++11 · Modern Revolution · Compiler flag: -std=c++11
Explanation
The `explicit` keyword can now be applied to conversion operators, preventing implicit type conversions that could lead to subtle bugs while still allowing explicit casts.
Real-World Scenario
A smart handle class that converts to `bool` for null-checking without accidentally participating in arithmetic expressions.
Quick Snippet
snippet.cpp
class Handle {
int fd;
public:
explicit operator bool() const { return fd >= 0; }
};
// if (handle) {} // OK: explicit bool in boolean context
// int x = handle; // Error: no implicit conversionFull Example
explicit_conversion.cpp
// CodeNebula - C++11 Example: Explicit Conversion Operators
// Compile: g++ -std=c++11 -Wall -Wextra -o example explicit_conversion.cpp
// Demonstrates explicit conversion operators introduced in C++11. Without
// 'explicit', conversion operators can cause surprising implicit conversions.
// Marking them explicit requires a cast or boolean context, improving safety.
#include <iostream>
#include <string>
// Real-world scenario: a safe boolean wrapper (like smart pointers)
class OptionalInt {
int value_;
bool hasValue_;
public:
OptionalInt() : value_(0), hasValue_(false) {}
explicit OptionalInt(int v) : value_(v), hasValue_(true) {}
// Explicit conversion to bool (safe for if-statements)
explicit operator bool() const
{
return hasValue_;
}
int value() const { return value_; }
bool has_value() const { return hasValue_; }
};
// Without explicit: dangerous implicit conversions
class UnsafeHandle {
int id_;
public:
UnsafeHandle(int id) : id_(id) {}
// Non-explicit: allows int x = handle; silently
operator int() const { return id_; }
};
// With explicit: safe, requires intentional cast
class SafeHandle {
int id_;
public:
explicit SafeHandle(int id) : id_(id) {}
explicit operator int() const { return id_; }
int id() const { return id_; }
};
// Percentage class with explicit double conversion
class Percentage {
double value_;
public:
explicit Percentage(double v) : value_(v) {}
explicit operator double() const { return value_ / 100.0; }
double raw() const { return value_; }
};
int main()
{
// ------------------------------------------------------------------
// 1. Explicit operator bool (the most common use case)
// ------------------------------------------------------------------
OptionalInt empty;
OptionalInt present(42);
std::cout << "=== Explicit operator bool ===" << std::endl;
if (present) {
std::cout << " present has value: " << present.value() << std::endl;
}
if (!empty) {
std::cout << " empty has no value" << std::endl;
}
// bool b = present; // ERROR: explicit prevents implicit conversion
bool b = static_cast<bool>(present); // OK: explicit cast
std::cout << " static_cast<bool>(present): " << b << std::endl;
std::cout << std::endl;
// ------------------------------------------------------------------
// 2. Unsafe (non-explicit) conversion operator
// ------------------------------------------------------------------
UnsafeHandle uh(42);
int x = uh; // compiles! implicit conversion
int y = uh + 10; // compiles! uh silently becomes int
std::cout << "=== Unsafe (non-explicit) ===" << std::endl;
std::cout << " int x = handle: " << x << std::endl;
std::cout << " handle + 10: " << y << " (implicit conversion!)" << std::endl;
std::cout << std::endl;
// ------------------------------------------------------------------
// 3. Safe (explicit) conversion operator
// ------------------------------------------------------------------
SafeHandle sh(42);
// int a = sh; // ERROR: no implicit conversion
// int b = sh + 10; // ERROR: no implicit conversion
int a = static_cast<int>(sh); // OK: explicit cast
int c = static_cast<int>(sh) + 10;
std::cout << "=== Safe (explicit) ===" << std::endl;
std::cout << " static_cast<int>(sh): " << a << std::endl;
std::cout << " static_cast<int>(sh) + 10: " << c << std::endl;
std::cout << " sh.id(): " << sh.id() << std::endl;
std::cout << std::endl;
// ------------------------------------------------------------------
// 4. Percentage with explicit double conversion
// ------------------------------------------------------------------
Percentage score(85.5);
// double d = score; // ERROR: explicit
double d = static_cast<double>(score); // OK: 0.855
std::cout << "=== Percentage ===" << std::endl;
std::cout << " raw value: " << score.raw() << "%" << std::endl;
std::cout << " as double: " << d << std::endl;
std::cout << std::endl;
// ------------------------------------------------------------------
// 5. Explicit bool in logical expressions (contextual conversion)
// ------------------------------------------------------------------
OptionalInt opt1(10);
OptionalInt opt2(20);
std::cout << "=== Contextual bool conversion ===" << std::endl;
// These work because &&, ||, !, ?: use contextual conversion to bool
std::cout << " opt1 && opt2 : " << (opt1 && opt2 ? "both set" : "not both") << std::endl;
std::cout << " opt1 || empty : " << (opt1 || empty ? "at least one" : "none") << std::endl;
std::cout << " !empty : " << (!empty ? "true" : "false") << std::endl;
return 0;
}
/*
Expected output:
=== Explicit operator bool ===
present has value: 42
empty has no value
static_cast<bool>(present): 1
=== Unsafe (non-explicit) ===
int x = handle: 42
handle + 10: 52 (implicit conversion!)
=== Safe (explicit) ===
static_cast<int>(sh): 42
static_cast<int>(sh) + 10: 52
sh.id(): 42
=== Percentage ===
raw value: 85.5%
as double: 0.855
=== Contextual bool conversion ===
opt1 && opt2 : both set
opt1 || empty : at least one
!empty : true
*/
Run command
g++ -std=c++11 -Wall -Wextra -o example explicit_conversion.cpp