Explizite Typwandlungen in Funktionsschreibweise in C++
Manchmal hat ein Wert eines fundamentalen Typs, wie der durch ein Literal gegebene Ausdruck »5« oder der durch eine Summe gegebene Wert »5 + 2« keinen Namen und belegt zur Laufzeit eines Programms auch nicht unbedingt Speicherplatz.
Es ist möglich auch Ausdrücke für Exemplare ohne eine Definition einer Variablen anzugeben. Solche Exemplare haben dann als keinen Namen. Sie werden auch nicht dauerhaft gespeichert, sondern nur solange wie sie erkennbar benötigt werden.
Solche Exemplare werden auch temporär oder Temporär genannt.
Solche Exemplare können durch eine explizite Typkonvertierung in Funktionsschreibweise (explicit type conversion (functional notation) ) oder als Wert anderer Ausdrücke entstehen. Ihre Lebenszeit endet normalerweise mit der Auswertung des sie enthaltenden Ausdrucks.
Das folgende Programmbeispiel zeigt die explizite Typkonvertierung in Funktionsschreibweise bei einem fundamentalen und bei einem benutzerdefiniertem Typ.
main.cpp
#include <iostream> /* ::std::cout */
#include <ostream> /* << */
#include <string> /* ::std::string */#include <initializer_list>
int main()
{ ::std::cout << '>' << int() << "<\n";
::std::cout << '>' << int{} << "<\n";::std::cout << '>' << int( 2 )<< "<\n";
::std::cout << '>' << int{ 2 }<< "<\n";::std::cout << '>' << ::std::string() << "<\n";
::std::cout << '>' << ::std::string{} << "<\n";::std::cout << '>' << ::std::string( "abc" )<< "<\n";
::std::cout << '>' << ::std::string{ "abc" }<< "<\n";::std::cout << '>' << ::std::string( 65, 'A' )<< "<\n";
::std::cout << '>' << ::std::string{ 65, 'A' }<< "<\n"; }::std::cout
>0<
>0<>2<
>2<><
><>abc<
>abc<>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA<
>AA<
Die Lebensdauer der in dem obenstehendem Programm erzeugten temporären Objekte endet jeweils mit der Auswertung der sie enthaltenden Ausgabeausdrücke.
Bei leeren Klammern wird in der Regel eine Wertinitialisierung durchgeführt. Bei einer Variablendefinition kann es vorkommen, daß leere runde Klammern dazu führen, daß diese nicht wie beabsichtigt verstanden wird. Bei der oben gezeigten explizite Typkonvertierung in Funktionsschreibweise mit leeren Klammern besteht dieses Risiko nicht. Die runden leeren Klammern haben dieselbe Bedeutung wie geschweifte leere Klammern, in beiden Fällen erfolgt eine Wertinitialisierung.
Falls die Klammern nur einen Ausdruck enthalten, so wird eine Typkonversion wie bei einem cast-Ausdruck durchgeführt.
Falls mehrere Ausdrücke in runden Klammern verwendet werden, so wird eine direkte Initialisierung durchgeführt, deren Bedeutung der Dokumentation der Klasse entnommen werden kann.
Falls mehrere Ausdrücke in geschweiften Klammern verwendet werden, so wird eine direkte Initialisierung mit Initialisierungsliste durchgeführt, deren Bedeutung der Dokumentation der Klasse entnommen werden kann.
An einigen Stellen ist eine implizite Typkonversion nicht erlaubt. In entsprechenden Fällen kann es dann helfen, eine explizite Typkonversion, wie sie gerade erklärt wurde, einzusetzen.
Typnamen aus mehreren lexikalischen Einheiten
Bei Typnamen aus mehreren lexikalischen Einheiten kann die Funktionsschreibweise nicht verwendet werden.
main.cpp
#include <iostream> /* ::std::cout */
#include <ostream> /* << */#include <initializer_list>
int main()
{ ::std::cout << '>' << unsigned int( 2 )<< "<\n"; }- Protokoll
error: expected primary-expression before 'unsigned'
| { ::std::cout << '>' << unsigned int( 2 )<< "<\n"; }
| ^~~~~~~~
Temporäre Objekte in Definitionen
Das folgende Programmbeispiel zeigt die explizite Typkonvertierung in Funktionsschreibweise mit nachfolgender Kopie des Wertes in eine Variable mit Blocklebensdauer. Der Wert (Zustand des Objekts) bleibt in diesem Falle erhalten, weil er in ein anderes Objekt mit längerer Lebensdauer kopiert wird, während das zunächst erzeugte temporäre Objekt nur während der Ausführung der Definition existiert.
main.cpp
#include <iostream> /* ::std::cout */
#include <ostream> /* << */
#include <string> /* ::std::string */int main()
{ ::std::string const s = ::std::string( "abc" );
::std::cout << s << '\n'; }::std::cout
abc
Typumformungen in Funktionsschreibweise in C++
(Andere Variante derselbe Lektion!)
- C++ -draft von 2014
n4296
- 5.2.3 Explicit type conversion (functional notation) [expr.type.conv]
- Konstruiert Wert des angegebenen Typs.
- Bei einem Argument entsprecht es einer Typumformung
- Bei mehreren Argumenten entspricht es einer Deklaration mit einem Namen vor der öffnenden Klammer, der Wert des Ausdrucks ist dann der Wert des deklarierten Objekts (als prvalue) (An dieser Stelle des Kurses wurde „prvalue“ noch nicht erklärt, es kann aber vorerst ignoriert werden)
- Mit leeren Klammern wird ein Wert (als prvalue) notiert, welcher der Wert eines wertinitialisierten Objekts des angegebenen Typs ist
- Wenn geschweifte Klammern verwendet werden, ist der Wert der Wert (als prvalue) eines temporären Objekt des angegebenen Typs, das aus der angegebenen Initialisierungsliste direkt-Listen-initialisiert wurde.
main.cpp
#include <iostream>
#include <ostream>
int main()
{ ::std::cout << int( 2 )<< '\n';
::std::cout << int() << '\n';
::std::cout << int{ 2 }<< '\n';
::std::cout << int{} << '\n';::std::cout << ::std::string( "abc" )<< '\n';
::std::cout << ::std::string() << '\n';
::std::cout << ::std::string{ "abc" }<< '\n';
::std::cout << ::std::string{} << '\n'; }::std::cout
2
0
2
0
abc
abc
.In dem folgenden Zitat steht »a« nicht nur für einen einzelnen Ausdruck, sondern kann auch für eine Liste von Ausdrücken stehen!
Zitat
- The initialization that occurs in the forms
- T x(a);
- T x{a};
- as well as in new expressions (5.3.4), static_cast expressions (5.2.9), functional notation type conversions
- (5.2.3), mem-initializers (12.6.2), and the braced-init-list form of a condition is called direct-initialization.
Beispiel
Getrennte Erzeugung
main.cpp
#include <algorithm>
#include <initializer_list>
#include <iostream>
#include <ostream>
#include <string>
#include <vector>int main()
{ { ::std::vector< ::std::pair< int, int >>v;
::std::pair< int, int > const p{ 4, 5 };
::std::pair< int, int > const q{ 6, 7 };
v.push_back( p );
v.push_back( q );
::std::cout << v.at( 0 ).first << '\n';
::std::cout << v.at( 0 ).second << '\n';
::std::cout << v.at( 1 ).first << '\n';
::std::cout << v.at( 1 ).second << '\n'; } }- Protokoll
4
5
6
7
Erzeugung in Funktionsschreibweise, es ist nun einfacher noch ein weiteres Paar hinzuzufügen (allerdings wäre hier emplace_back noch besser)
main.cpp
#include <algorithm>
#include <initializer_list>
#include <iostream>
#include <ostream>
#include <string>
#include <vector>int main()
{ { ::std::vector< ::std::pair< int, int >>v;
v.push_back( ::std::pair < int, int >{ 4, 5 });
v.push_back( ::std::pair < int, int >{ 6, 7 });
::std::cout << v.at( 0 ).first << '\n';
::std::cout << v.at( 0 ).second << '\n';
::std::cout << v.at( 1 ).first << '\n';
::std::cout << v.at( 1 ).second << '\n'; } }- Protokoll
4
5
6
7
Beispiel
main.cpp
#include <iostream>
#include <ostream>
#include <random>int main()
{ ::std::cout << ::std::random_device{}.entropy() << "\n"; }0
Beispiel
Unten wird keine Variable a, sondern eine Funktion "std::atomic<int> a(int (*)())" deklariert
main.cpp
#include <iostream> /* ::std::cout */
#include <ostream> /* << */
#include <atomic> /* ::std::atomic */
#include <initializer_list>int main()
{ ::std::atomic<int> a( int() ); ::std::cout << a << '\n'; }transcript
1
F:\r\j\autocomp\main.cpp:9:18: warning: implicit conversion between pointer-to-function and pointer-to-object is a Microsoft extension [clang-diagnostic-microsoft-cast]