cpp/language/explicit: Difference between revisions
From cppreference.com
m +Keywords |
c -> c/core. |
||
| Line 4: | Line 4: | ||
===Syntax=== | ===Syntax=== | ||
{{sdsc begin}} | {{sdsc begin}} | ||
{{sdsc|num=1| | {{sdsc|num=1| | ||
{{ttb|explicit}} | {{ttb|explicit}} | ||
}} | }} | ||
{{sdsc|num=2|notes={{mark since c++20}}| | {{sdsc|num=2|notes={{mark since c++20}}| | ||
{{ttb|explicit (}} {{spar|expression}} {{ttb|) }} | {{ttb|explicit (}} {{spar|expression}} {{ttb|)}} | ||
}} | }} | ||
{{sdsc end}} | {{sdsc end}} | ||
{{par begin}} | {{par begin}} | ||
{{par|{{spar|expression}}|{{rlp|constant expression#Converted constant expression|contextually converted constant expression of type {{c|bool}}}}}} | {{par|{{spar|expression}}|{{rlp|constant expression#Converted constant expression|contextually converted constant expression of type {{c|bool}}}}}} | ||
{{par end}} | {{par end}} | ||
@1@ Specifies that a constructor {{rev inl|since=c++11|or conversion function}}{{rev inl|since=c++17|or {{rlp|ctad|deduction guide}}}} is explicit, that is, it cannot be used for | |||
@1@ Specifies that a constructor {{rev inl|since=c++11|or conversion function}}{{rev inl|since=c++17|or {{rlp|ctad|deduction guide}}}} is explicit, that is, it cannot be used for |implicit and |copy-initialization. | |||
{{rrev|since=c++20| | {{rrev|since=c++20| | ||
@2@ The {{c|explicit}} specifier may be used with a constant expression. The function is explicit if and only if that constant expression evaluates to {{c|true}}. | @2@ The {{c|explicit}} specifier may be used with a constant expression. The function is explicit if and only if that constant expression evaluates to {{c|true}}. | ||
}} | }} | ||
| Line 24: | Line 25: | ||
===Notes=== | ===Notes=== | ||
A constructor {{rev inl|until=c++11|with a single non-default parameter}} that is declared without the function specifier {{c|explicit}} is called a {{rlp|converting constructor}}. | A constructor {{rev inl|until=c++11|with a single non-default parameter}} that is declared without the function specifier {{c|explicit}} is called a {{rlp|converting constructor}}. | ||
Both constructors (other than {{rlp| | Both constructors (other than {{rlp||copy}}/{{rlp||move}}) and user-defined conversion functions may be function templates; the meaning of {{|explicit}} does not change. | ||
{{rrev|since=c++20|1= | {{rrev|since=c++20|1= | ||
A {{ttb|(}} token that follows {{ | A {{ttb|(}} token that follows {{|explicit}} is parsed as part of the explicit specifier: | ||
{{source|1= | {{source|1= | ||
struct S | struct S | ||
| Line 38: | Line 39: | ||
}} | }} | ||
}} | }} | ||
{{feature test macro|value=201806L|std=C++20|__cpp_conditional_explicit|{{c|explicit | {{feature test macro|value=201806L|std=C++20|__cpp_conditional_explicit|{{c|explicit}}}} | ||
===Keywords=== | ===Keywords=== | ||
| Line 47: | Line 48: | ||
struct A | struct A | ||
{ | { | ||
A(int) { } // converting constructor | A(int) {} // converting constructor | ||
A(int, int) { } // converting constructor (C++11) | A(int, int) {} // converting constructor (C++11) | ||
operator bool() const { return true; } | operator bool() const { return true; } | ||
}; | }; | ||
| Line 54: | Line 55: | ||
struct B | struct B | ||
{ | { | ||
explicit B(int) { } | explicit B(int) {} | ||
explicit B(int, int) { } | explicit B(int, int) {} | ||
explicit operator bool() const { return true; } | explicit operator bool() const { return true; } | ||
}; | }; | ||
| Line 69: | Line 70: | ||
bool na1 = a1; // OK: copy-initialization selects A::operator bool() | bool na1 = a1; // OK: copy-initialization selects A::operator bool() | ||
bool na2 = static_cast<bool>(a1); // OK: static_cast performs direct-initialization | bool na2 = static_cast<bool>(a1); // OK: static_cast performs direct-initialization | ||
// B b1 = 1; // error: copy-initialization does not consider B::B(int) | // B b1 = 1; // error: copy-initialization does not consider B::B(int) | ||
B b2(2); // OK: direct-initialization selects B::B(int) | B b2(2); // OK: direct-initialization selects B::B(int) | ||
| Line 78: | Line 79: | ||
// bool nb1 = b2; // error: copy-initialization does not consider B::operator bool() | // bool nb1 = b2; // error: copy-initialization does not consider B::operator bool() | ||
bool nb2 = static_cast<bool>(b2); // OK: static_cast performs direct-initialization | bool nb2 = static_cast<bool>(b2); // OK: static_cast performs direct-initialization | ||
[](...){}(a4, a5, na1, na2, b5, nb2); // | [](...){}(a4, a5, na1, na2, b5, nb2); // warnings | ||
} | } | ||
}} | }} | ||
Latest revision as of 07:29, 12 August 2024
Syntax
explicit
|
(1) | ||||||||
explicit ( expression )
|
(2) | (since C++20) | |||||||
| expression | - | contextually converted constant expression of type bool
|
1) Specifies that a constructor or conversion function(since C++11)or deduction guide(since C++17) is explicit, that is, it cannot be used for implicit conversions and copy-initialization.
|
2) The
explicit specifier may be used with a constant expression. The function is explicit if and only if that constant expression evaluates to true. |
(since C++20) |
The explicit specifier may only appear within the decl-specifier-seq of the declaration of a constructor or conversion function(since C++11) within its class definition.
Notes
A constructor with a single non-default parameter(until C++11) that is declared without the function specifier explicit is called a converting constructor.
Both constructors (other than copy/move) and user-defined conversion functions may be function templates; the meaning of explicit does not change.
|
A struct S
{
explicit (S)(const S&); // error in C++20, OK in C++17
explicit (operator int)(); // error in C++20, OK in C++17
};
|
(since C++20) |
| Feature-test macro | Value | Std | Feature |
|---|---|---|---|
__cpp_conditional_explicit |
201806L |
(C++20) | conditional explicit
|
Keywords
Example
Run this code
struct A
{
A(int) {} // converting constructor
A(int, int) {} // converting constructor (C++11)
operator bool() const { return true; }
};
struct B
{
explicit B(int) {}
explicit B(int, int) {}
explicit operator bool() const { return true; }
};
int main()
{
A a1 = 1; // OK: copy-initialization selects A::A(int)
A a2(2); // OK: direct-initialization selects A::A(int)
A a3 {4, 5}; // OK: direct-list-initialization selects A::A(int, int)
A a4 = {4, 5}; // OK: copy-list-initialization selects A::A(int, int)
A a5 = (A)1; // OK: explicit cast performs static_cast
if (a1) { } // OK: A::operator bool()
bool na1 = a1; // OK: copy-initialization selects A::operator bool()
bool na2 = static_cast<bool>(a1); // OK: static_cast performs direct-initialization
// B b1 = 1; // error: copy-initialization does not consider B::B(int)
B b2(2); // OK: direct-initialization selects B::B(int)
B b3 {4, 5}; // OK: direct-list-initialization selects B::B(int, int)
// B b4 = {4, 5}; // error: copy-list-initialization does not consider B::B(int, int)
B b5 = (B)1; // OK: explicit cast performs static_cast
if (b2) { } // OK: B::operator bool()
// bool nb1 = b2; // error: copy-initialization does not consider B::operator bool()
bool nb2 = static_cast<bool>(b2); // OK: static_cast performs direct-initialization
[](...){}(a4, a5, na1, na2, b5, nb2); // suppresses “unused variable” warnings
}