Initializes an object from explicit set of constructor arguments.
T object ( arg ); T object | (1) | |
T object { arg }; | (2) | (since C++11) |
T ( other ) T | (3) | |
static_cast< T >( other ) | (4) | |
new T(args, ...) | (5) | |
Class::Class() : member(args, ...) {... | (6) | |
[arg](){... | (7) | (since C++11) |
Direct initialization is performed in the following situations:
The effects of direct initialization are:
T is a class type,
| (since C++17) |
T are examined and the best match is selected by overload resolution. The constructor is then called to initialize the object. T is a non-class type but the source type is a class type, the conversion functions of the source type and its base classes, if any, are examined and the best match is selected by overload resolution. The selected user-defined conversion is then used to convert the initializer expression into the object being initialized. T, and the initial value of the object being initialized is the (possibly converted) value. Direct-initialization is more permissive than copy-initialization: copy-initialization only considers non-explicit constructors and non-explicit user-defined conversion functions, while direct-initialization considers all constructors and all user-defined conversion functions.
In case of ambiguity between a variable declaration using the direct-initialization syntax (1) (with round parentheses) and a function declaration, the compiler always chooses function declaration. This disambiguation rule is sometimes counter-intuitive and has been called the most vexing parse.
#include <iterator>
#include <string>
#include <fstream>
int main()
{
std::ifstream file("data.txt");
// the following is a function declaration:
std::string str(std::istreambuf_iterator<char>(file),
std::istreambuf_iterator<char>());
// it declares a function called str, whose return type is std::string,
// first parameter has type std::istreambuf_iterator<char> and the name "file"
// second parameter has no name and has type std::istreambuf_iterator<char>(),
// which is rewritten to function pointer type std::istreambuf_iterator<char>(*)()
// pre-c++11 fix: extra parentheses around one of the arguments
std::string str( (std::istreambuf_iterator<char>(file) ),
std::istreambuf_iterator<char>());
// post-C++11 fix: list-initialization for any of the arguments
std::string str(std::istreambuf_iterator<char>{file}, {});
}Similarly, in the case of an ambiguity between a expression statement with a function-style cast expression (3) as its leftmost subexpression and a declaration statement, the ambiguity is resolved by treating it as a declaration. This disambiguation is purely syntactic: it doesn't consider the meaning of names occurring in the statement other than whether they are type names.
struct M { };
struct L { L(M&); };
M n;
void f() {
M(m); // declaration, equivalent to M m;
L(n); // ill-formed declaration
L(l)(m); // still a declaration
}#include <string>
#include <iostream>
#include <memory>
struct Foo {
int mem;
explicit Foo(int n) : mem(n) {}
};
int main()
{
std::string s1("test"); // constructor from const char*
std::string s2(10, 'a');
std::unique_ptr<int> p(new int(1)); // OK: explicit constructors allowed
// std::unique_ptr<int> p = new int(1); // error: constructor is explicit
Foo f(2); // f is direct-initialized:
// constructor parameter n is copy-initialized from the rvalue 2
// f.mem is direct-initialized from the parameter n
// Foo f2 = 2; // error: constructor is explicit
std::cout << s1 << ' ' << s2 << ' ' << *p << ' ' << f.mem << '\n';
}Output:
test aaaaaaaaaa 1 2
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
http://en.cppreference.com/w/cpp/language/direct_initialization