Direct-initialization
Initialisiert ein Objekt aus einem expliziten Satz von Konstruktorargumenten.
Inhaltsverzeichnis |
Syntax
T
Objekt
(
arg
);
T
Objekt
|
(1) | ||||||||
T
Objekt
{
arg
};
|
(2) | (seit C++11) | |||||||
T
(
other
)
T
|
(3) | ||||||||
static_cast<
T
>(
other
)
|
(4) | ||||||||
new
T
(
args, ...
)
|
(5) | ||||||||
Klasse
::
Klasse
()
:
Mitglied
(
args, ...
)
{
...
}
|
(6) | ||||||||
[
arg
]() {
...
}
|
(7) | (seit C++11) | |||||||
Erklärung
Direkte Initialisierung wird in den folgenden Situationen durchgeführt:
Die Auswirkungen der Direktinitialisierung sind:
-
Wenn
Tein Array-Typ ist,
|
(bis C++20) |
struct A { explicit A(int i = 0) {} }; A a[2](A(1)); // OK: initializes a[0] with A(1) and a[1] with A() A b[2]{A(1)}; // error: implicit copy-list-initialization of b[1] // from {} selected explicit constructor |
(seit C++20) |
-
Wenn
Tein Klassentyp ist,
|
(seit C++17) |
-
-
die Konstruktoren von
Twerden untersucht und die beste Übereinstimmung wird durch Überladungsauflösung ausgewählt. Der Konstruktor wird dann aufgerufen, um das Objekt zu initialisieren.
-
die Konstruktoren von
struct B { int a; int&& r; }; int f(); int n = 10; B b1{1, f()}; // OK, lifetime is extended B b2(1, f()); // well-formed, but dangling reference B b3{1.0, 1}; // error: narrowing conversion B b4(1.0, 1); // well-formed, but dangling reference B b5(1.0, std::move(n)); // OK |
(seit C++20) |
-
Andernfalls, falls
Tein Nicht-Klassentyp ist, aber der Quelltyp ein Klassentyp ist, werden die Konvertierungsfunktionen des Quelltyps und seiner Basisklassen, falls vorhanden, geprüft und die beste Übereinstimmung durch Überladungsauflösung ausgewählt. Die ausgewählte benutzerdefinierte Konvertierung wird dann verwendet, um den Initialisierungsausdruck in das zu initialisierende Objekt umzuwandeln. -
Andernfalls, falls
Tbool ist und der Quelltyp std::nullptr_t ist, ist der Wert des initialisierten Objekts false . -
Andernfalls werden
Standardkonvertierungen
verwendet, falls notwendig, um den Wert von
other
in die cv-unqualifizierte Version von
Tumzuwandeln, und der Anfangswert des zu initialisierenden Objekts ist der (möglicherweise konvertierte) Wert.
Hinweise
Direct-Initialisierung ist restriktiver als Copy-Initialisierung: Copy-Initialisierung berücksichtigt nur nicht- explicit Konstruktoren und nicht-explizite benutzerdefinierte conversion functions , während Direct-Initialisierung alle Konstruktoren und alle benutzerdefinierten Konversionfunktionen berücksichtigt.
Im Falle von Mehrdeutigkeit zwischen einer Variablendeklaration mit der Direktinitialisierungssyntax (1) (mit runden Klammern) und einer Funktionsdeklaration , wählt der Compiler stets die Funktionsdeklaration. Diese Disambiguierungsregel ist manchmal kontraintuitiv und wurde als most vexing parse bezeichnet.
#include <fstream> #include <iterator> #include <string> int main() { std::ifstream file("data.txt"); // Das Folgende ist eine Funktionsdeklaration: std::string foo1(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()); // Sie deklariert eine Funktion namens foo1, deren Rückgabetyp std::string ist, // der erste Parameter hat den Typ std::istreambuf_iterator<char> und den Namen "file", // der zweite Parameter hat keinen Namen und den Typ std::istreambuf_iterator<char>(), // was in den Funktionszeigertyp std::istreambuf_iterator<char>(*)() umgeschrieben wird // Pre-C++11 Korrektur (um eine Variable zu deklarieren) - zusätzliche Klammern um einen // der Parameter setzen: std::string str1((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()); // Post-C++11 Korrektur (um eine Variable zu deklarieren) - Listeninitialisierung für einen // der Parameter verwenden: std::string str2(std::istreambuf_iterator<char>{file}, {}); }
Beispiel
#include <iostream> #include <memory> #include <string> struct Foo { int mem; explicit Foo(int n) : mem(n) {} }; int main() { std::string s1("test"); // Konstruktor von const char* std::string s2(10, 'a'); std::unique_ptr<int> p(new int(1)); // OK: explizite Konstruktoren erlaubt // std::unique_ptr<int> p = new int(1); // Fehler: Konstruktor ist explizit Foo f(2); // f ist direkt initialisiert: // Konstruktorparameter n ist kopierinitialisiert vom Rvalue 2 // f.mem ist direkt initialisiert vom Parameter n // Foo f2 = 2; // Fehler: Konstruktor ist explizit std::cout << s1 << ' ' << s2 << ' ' << *p << ' ' << f.mem << '\n'; }
Ausgabe:
test aaaaaaaaaa 1 2