2016-12-23 37 views
3

TL;博士:如果它是由前template<typename Something>拷貝構造函數不叫,那Something在構造函數簽名中使用。g ++不會調用複製構造函數,如果它是模板?


證明的概念(ideone):

#include <cstdio> 

template<typename T> 
class Test { 
private: 
    T value_; 

public: 
    mutable bool has_copies; 

    Test(const T& value) : value_(value), has_copies(false) {} 

    template<typename Related> // remove template here to fix behavior 
    Test(const Test<Related>& t) { 
     printf("In copy constructor\n"); 
     value_ = t.value_; 
     has_copies = true; 
     t.has_copies = true; 
    } 
}; 

int main() { 
    Test<int> t1(42); 
    printf("Before constructor\n"); 
    Test<int> t2(t1); 
    printf("After constructor:\n"); 
    printf(" t1 thinks it %s copies\n", t1.has_copies ? "has" : "doesn't have"); 
    printf(" t2 thinks it %s copies\n", t2.has_copies ? "has" : "doesn't have"); 
} 

輸出:

Before constructor 
After constructor: 
    t1 thinks it doesn't have copies 
    t2 thinks it doesn't have copies 

通知如何不打印In copy constructor

使複製構造函數非模板化(即在簽名中刪除template<typename Related>並將Related更改爲T)爲我解決了這個問題。

$ g++ --version 
g++ (GCC) 6.2.1 20160830 

編譯&執行命令:

g++ -Wall -Wextra -pedantic -std=c++11 -O2 -Wshadow -Wformat=2 -Wfloat-equal -Wconversion -Wlogical-op -Wcast-qual -Wcast-align -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -D_FORTIFY_SOURCE=2 -fsanitize=address -fsanitize=undefined -fno-sanitize-recover -fstack-protector "test.cpp" -o "test" && "test" 

這是怎麼回事嗎?

回答

5

函數模板永遠不可能是複製構造函數,即使使用明顯使其與複製構造函數的預期簽名相匹配的類型實例化。參見[class.copy/2]:

甲非模板構造用於類X是拷貝構造如果它的第一個參數是X型&,常量X &,易失性X &或const揮發性X &的,並且沒有其他參數,否則所有其他參數都有默認參數。

所有班級有一個隱含生成的拷貝構造函數,如果沒有一個用戶聲明的一個(有時這可以被定義爲刪除),有簽名:

Test(Test const &) = default; 

當你寫Test<int> t2(t1);,重載解析選擇複製構造函數而不是模板函數,因爲非模板比模板更受歡迎,所有其他事物都相同。

請注意,如果您將模板功能更改爲Test(Test<Related>& t),那麼現在將通過複製構造函數選擇它:「其他所有事物」不再相同,並且實例化模板以完全匹配Test<int>優於轉換添加const以匹配複製構造函數。

0

cppreference

類T的拷貝構造引用是一個非模板構造器,其第一個參數是T&const T&volatile T&,或const volatile T&,並且或者沒有其他參數,或其餘參數都有默認值。

因此,您的構造函數在作爲模板時失敗,並且沒有正確的參數類型。

相關問題