2015-05-08 116 views
2

可能我對explicit的理解不夠,但是我想知道爲什麼在下面的代碼中,當我聲明後者爲explicit時,複製構造函數不會被非反參考構造函數隱藏。C++顯式通用引用構造函數不隱藏複製構造函數?

struct A 
{ 
    A() = default; 

    template<typename T> 
    A(T&& t) { std::cout<<"hides copy constructor"<<std::endl; } 
}; 

struct A_explicit 
{ 
    A_explicit() = default; 

    template<typename T> 
    explicit A_explicit(T&& t) { std::cout<<"does not hide copy constructor?"<<std::endl; } 
}; 

int main() 
{ 
    A a; 
    auto b = a; (void) b; //prints "hides copy constructor" 

    A_explicit a_exp;  
    auto b_exp = a_exp; (void) b_exp; //prints nothing 
} 

DEMO

那是一個通用的解決方案,而不是SFINAE東西,一個原本適用於防止躲在A(例如通過std::enable_if_t<!std::is_same<std::decay_t<T>, A>::value>,見here)?

+0

對於那些有興趣,[這裏](http://en.cppreference.com/w/cpp/language/converting_constructor)是我根據答案找到的一些解釋。 – davidhigh

回答

5

標記爲explicit的構造函數在複製初始化期間不參與重載解析(A a = b;等)。

它確實參與了複製列表初始化(A a = {b1};),並且如果選擇了該程序,則會導致該程序不合格。

...除非花括號內的東西是A或從中派生出來的類,在這種情況下,最近的缺陷報告改變了規則,說在這種特殊情況下執行復制初始化 - 因此explicit構造函數再次被完全忽略。

非常可教,我知道。

那是一個通用的解決方案,而不是SFINAE東西,一個將適用 否則以防止在隱藏?

號因爲它們的構造依然贏得直接初始化重載解析:

A_explicit a, b(a); // will call the constructor taking a forwarding reference 
6

A中,複製構造函數是未隱藏。編譯器像往常一樣隱式聲明它。它只是失去超載分辨率,因爲它的參數類型(const A&)與構造函數模板(A&)的專業化參數相比具有額外的cv限定。如果你願意

auto b = static_cast<const A&>(a); 

你會看到複製構造函數會被調用。

A_explicit中,該模板根本沒有作爲重載解析的候選提交,因爲它被聲明爲explicit。隱式聲明的拷貝構造函數仍然存在,就像它在A中一樣,因此它被調用。

+0

謝謝,但我沒有得到答案。你能否詳細解釋一下複製'A_explicit'時會發生什麼?例如,你的意思是*該模板沒有被提交作爲重載解析的候選*。 – davidhigh

+1

@davidhigh通過實例化模板生成的函數根本沒有機會被調用,因爲複製初始化需要非顯式構造函數。而對於'A',它與複製構造函數的平等對待,並選擇最佳匹配。 – Brian