struct X {
X() {}
template X(const T&) { puts("templated copy ctor"); }
template X& operator=(const T&) { puts("templated assign"); return *this; }
};
int main() {
X x1;
X x2(x1); // 輸出?
X x3; x3 = x1; // 輸出?
}
**輸出:空!** 兩個模板**均未被調用**。
X&, const X&, volatile X&, const volatile X&,且**無其他參數**或其餘參數有默認值。X, X&, const X&, volatile X&, const volatile X&。關鍵字:**非模板**。帶模板參數的構造/賦值函數**不算**拷貝構造/賦值運算符。
X **未顯式聲明**符合標準定義的拷貝構造/賦值運算符。const X&),模板版本需推導 T=X,排序較低。
4. 因此調用隱式版本,**無任何輸出**。
struct X {
X() {}
X(const X&) { puts("copy ctor"); } // 真正的拷貝構造
X& operator=(const X&) { puts("assign"); return *this; } // 真正的賦值
// 如需通用構造,放在後面或用 SFINAE 排除 X 自身
template>>
X(const T&) { puts("templated ctor"); }
};
= default / = delete 顯式控制隱式生成。X(X&&), operator=(X&&))若用戶聲明任意構造/析構/賦值,**不會**隱式生成移動操作(Rule of Five)。std::enable_if 或 Concepts (C++20)。| 場景 | 建議 |
|---|---|
| 管理資源(指標、句柄、文件) | 必須顯式實現「五大函數」或 =delete 禁止拷貝,改用移動語義/智能指標 |
| 僅含值類型成員 | 可 =default 或依賴隱式 |
含 const/引用成員 | 無法賦值,必須 =delete 賦值運算符 |
| 基類設計 | 虛析構,**protected** 非虛賦值防止切片 |
**「模板構造 ≠ 拷貝構造」**是 C++ 核心規則之一。隱式生成規則看似簡單,實則暗含「非模板優先、精確匹配優先」的重載決議邏輯。寫資源管理類時,務必顯式 =default/=delete/自定義,別讓編譯器替你決定。