8

我有以下代码:

bool c (a == b);

bool c {a == b};

其中 a 和 b 是一些相同类型的变量。

我想知道,以上两种初始化有什么区别,在什么情况下应该首选哪一种?任何形式的帮助将不胜感激。

4

3 回答 3

11

两种形式都是直接初始化

使用花括号{}进行初始化检查以缩小转换范围,如果发生这种转换,则会生成错误。不同于(). (gcc 默认发出警告,并且需要-Werror=narrowing编译器选项在发生缩小时生成错误。)

花括号的另一个用途{}统一初始化:使用相同的语法初始化带有和不带有构造函数的类型,例如:

template<class T, class... Args>
T create(Args&&... args) {
    T value{std::forward<Args>(args)...}; // <--- uniform initialization + perfect forwarding
    return value;
}

struct X { int a, b; };
struct Y { Y(int, int, int); };

int main() {
    auto x = create<X>(1, 2);    // POD
    auto y = create<Y>(1, 2, 3); // A class with a constructor.
    auto z = create<int>(1);     // built-in type
}

使用花括号{}进行初始化的唯一缺点是它与auto关键字的交互。auto推断{}std::initializer_list,这是一个已知问题,请参阅“Auto and braced-init-lists”

于 2015-08-20T10:00:56.987 回答
3

第一个是 C++03 风格的直接初始化。第二个是 C++11 风格的直接初始化,它额外检查缩小转换。Herb Sutter 在新代码中推荐以下内容:

auto c = <expression>;

或者当您想提交特定类型 T 时:

auto c = T{<expression>};

当 T 是具有重载构造函数的某个类时,花括号的一个已知缺点是,其中一个构造函数将 std::initializer_list 作为参数,例如 std::vector:

auto v = std::vector<int>{10}; // create vector<int> with one element = 10
auto v = std::vector<int>(10); // create vector<int> with 10 integer elements
于 2015-08-20T10:08:48.747 回答
2

现在我们有五种初始化形式。他们是

T x = expression;
T x = ( expression );
T x (  expression );
T x = { expression };
T x { expression };

每种形式都有自己的特点。:)

例如,假设您在全局命名空间中有以下声明

int x;

void f( int x ) { ::x = x; }
int g() { return x ; }
long h() { return x; } 

然后主要你可以写

int main()
{
    int x ( g() );
}

此代码将成功编译。

然而一个程序员错误地打错了

int main()
{
    int x; ( g() );
         ^^
}

哎呀!此代码也编译成功。:)

但是如果程序员会写

int main()
{
    int x = ( g() );
}

然后打错字

int main()
{
    int x; = ( g() );
         ^^
}

那么在这种情况下,代码将无法编译。

好吧,让我们假设程序员首先决定在初始化局部变量之前为全局变量 x 设置一个新值。

于是他写了

int main()
{
    int x ( f( 10 ), g() );
}

但是这段代码无法编译!

让我们插入等号

int main()
{
    int x = ( f( 10 ), g() );
}

现在代码编译成功!

那么牙套呢?

这段代码都没有

int main()
{
    int x { f( 10 ), g() };
}

也不是这个代码

int main()
{
    int x = { f( 10 ), g() };
}

编译!:)

现在程序员决定使用函数 h(),他写道

int main()
{
    int x ( h() );
}

并且他的代码编译成功。但一段时间后他决定使用牙套

int main()
{
    int x { h() };
}

哎呀!他的编译器发出错误

错误:在初始值设定项列表中,非常量表达式不能从“long”类型缩小到“int”

该程序决定使用类型说明符 auto。他尝试了两种方法

int main()
{
    auto x { 10 };
    x = 20;
}    

int main()    
{
    auto x = { 10 };
    x = 20;
}    

和......一些编译器编译了第一个程序但没有编译第二个程序,一些编译器没有编译这两个程序。:)

那么使用decltype呢?

例如程序员写的

int main()
{
    int a[] = { 1, 2 };
    decltype( auto ) b = a;
}    

而且他的编译器发出了错误!

但是当程序员像这样将 a 括在括号中时

int main()
{
    int a[] = { 1, 2 };
    decltype( auto ) b = ( a );
}    

代码编译成功!:)

现在程序员决定学习OOP。他写了一个简单的类

struct Int
{
    Int( int x = 0 ) : x( x ) {}
    int x;
};
    
int main()
{
    Int x = { 10 };    
}    

并且他的代码编译成功。但是程序员知道有函数说明符explicit,他决定使用它

struct Int
{
    explicit Int( int x = 0 ) : x( x ) {}
    int x;
};
    
int main()
{
    Int x = { 10 };    
}    

哎呀!他的编译器发出错误

error: chosen constructor is explicit in copy-initialization

程序员决定去掉赋值符号

struct Int
{
    explicit Int( int x = 0 ) : x( x ) {}
    int x;
};
    
int main()
{
    Int x { 10 };    
}    

并且他的代码编译成功!:)

于 2015-08-20T10:38:58.677 回答