2017-09-06 22 views
15

當我在統一初始化過程中使用尾隨逗號時,是否有任何潛在的語義差異?統一初始化中的尾隨逗號

std::vector<std::size_t> v1{5, }; // allowed syntax 
std::vector<std::size_t> v2{10}; 

我能否使用尾隨逗號使編譯器來選擇std::vector::vector(std::initializer_list<std::size_t>)構造函數,而不是std::vector::vector(std::size_t, const std::size_t &)還是有什麼其他的技巧與提到的語法?

我可以用它來檢測是否有std::initializer_list -constructor重載?

考慮下面的代碼,必須選擇哪個構造函數?

struct A { A(int) { ; } A(double, int = 3) { ; } }; 
A a{1}; 
A b{2, }; 

此代碼is accepted by gcc 8A(int)在兩種情況下被選中。

+0

第一個('std :: initializer_list'-constructor)總是s當選。 https://wandbox.org/permlink/Yy6VtcK5ISCbzZJp – songyuanyao

+0

無論如何,沒有理由'v2 {...}'調用任何構造函數,但只有'std :: initializer_list' ....只有'v2(。 ..)'會調用'std :: vector :: vector(std :: size_t ...)' – jpo38

+0

@songyuanyao是的,但如果只有構造函數具有一元和二元的arities,可能的,默認的函數參數初始值設定項和其他情況?在所有可想象的情況下,有沒有*語義差異? – Orient

回答

9

首先,C++語法規則使尾隨,可選,用於括號初始化列表。引用dcl.init/1

聲明者可以爲標識爲 的聲明指定初始值。標識符指定正在初始化的變量。在[dcl.init] 的其餘部分中描述的初始化過程也適用於由其他語法上下文指定的初始化,例如函數參數初始化([expr.call])或返回值初始化([ stmt.return])。

initializer: 
    brace-or-equal-initializer 
    (expression-list) 
brace-or-equal-initializer: 
    = initializer-clause 
    braced-init-list 
initializer-clause: 
    assignment-expression 
    braced-init-list 
braced-init-list: 
    { initializer-list ,opt } 
    { designated-initializer-list ,opt } 
    { } 

其次,你不能幾乎覆蓋重載解析系統。如果使用這種語法,它將始終使用std::initializer_list構造函數,並且此類構造函數可用。

dcl.init.list/2

構造函數是一個初始化列表構造如果它的第一個參數 是類型爲std :: initializer_list或參照 可能CV-合格的std :: initializer_list對於一些鍵入E,並且 要麼沒有其他參數,要麼所有其他參數都具有默認參數 。 [注意:初始化列表構造函數比list-initialization([over.match.list])中的其他構造函數更受青睞....


下面打印Using InitList程序:

#include <iostream> 
#include <initializer_list> 

struct X{ 
    X(std::initializer_list<double>){ std::cout << "Using InitList\n"; } 
    X(int){ std::cout << "Using Single Arg ctor\n"; } 
}; 

int main(){ 
    X x{5}; 
} 

儘管5是文字int型的,它應該是有意義的選擇,因爲它是一個單參數的構造函數完美搭配;並且std::initializer_list<double>構造函數想要一個double的列表。但是,規則有利於std::initializer_list<double>,因爲它的初始值設定項列表構造函數

其結果是,即使下面的程序將失敗,因爲收縮轉換:

#include <iostream> 
#include <initializer_list> 

struct Y{ 
    Y(std::initializer_list<char>){ std::cout << "Y Using InitList\n"; } 
    Y(int, int=4){ std::cout << "Y Using Double Arg ctor\n"; } 
}; 

int main(){ 
    Y y1{4777}; 
    Y y2{577,}; 
    Y y3{57,7777}; 
} 

在回答下面的評論,「如果有一種是的std :: initializer_list沒有超載,或它不是第一個構造函數的參數?「 - 然後重載解析不會選擇它。演示:

#include <iostream> 
#include <initializer_list> 

struct Y{ 
    Y(int, std::initializer_list<double>){ std::cout << "Y Using InitList\n"; } 
    Y(int, int=4){ std::cout << "Y Using Double Arg ctor\n"; } 
}; 

int main(){ 
    Y y1{4}; 
    Y y2{5,}; 
    Y y3{5,7}; 
} 

打印:

Y Using Double Arg ctor 
Y Using Double Arg ctor 
Y Using Double Arg ctor 

如果沒有初始化列表構造可用,那麼{initializer-list...,}初始化幾乎回落到直接初始化dcl.init/16,其語義包含在前面的段落dcl.init/16

+0

好的,如果有沒有用'std :: initializer_list'重載,或者它不是第一個構造函數的參數? – Orient

+0

@Orient,看到我更新的答案 – WhiZTiM

2

不是。該逗號是讓預處理器宏技巧無編譯錯誤的讓步。這對於您的數據類型或其大小沒有任何意義。