2017-07-17 30 views
8

後續的代碼不能編譯,因爲結構A不支持--操作。如果方法沒有進行類型檢查,爲什麼C++模板匹配?

struct A {}; 

struct B { 
    void Run() {} 
    A& Dec(A& a) { return --a; } 
}; 

int main(int argc, char** argv) { 
    B b; 
    b.Run(); 
} 

與此密碼相同。

struct A {}; 

template <class T> 
struct B { 
    void Run() {} 
    A& Dec(A& a) { return --a; } 
}; 

int main(int argc, char** argv) { 
    B<A> b; 
    b.Run(); 
} 

那麼爲什麼這個編譯(在C + + 11)?

struct A {}; 

template <class T> 
struct B { 
    void Run() {} 
    T& Dec(T& a) { return --a; } 
}; 

int main(int argc, char** argv) { 
    B<A> b; 
    b.Run(); 
} 

看來,實例化的模板不自動實例依賴於類型參數類型檢查,這意味着如果它的一些方法沒有模板甚至會匹配模板內未使用的方法。這是令人失望的,因爲我希望用SFINAE檢測的各種方法和運營商類型的適用性,但如果模板替換成功,即使到方法的調用將編譯時錯誤,該技術將無法正常工作。

+0

您仍然可以使用SFINAE來完全刪除「無效」方法。目前,檢測「B :: Dec(A&)」的存在將會成功。 – Jarod42

+2

您也可以強制實例化模板類以獲取錯誤:'template class B ;'。 – Jarod42

+1

[是否爲未使用的模板類方法生成了目標代碼?](https://stackoverflow.com/questions/183108/is-object-code-generated-for-unused-template-class-methods) – AndyG

回答

5

會議決定(由C++委員會),該模板類的方法只會有,如果他們在那裏使用實例化自己的身體。

這使得它更容易在硬錯誤的成本寫一些C++代碼使用它們時。

作爲這樣的一個例子,與std::vectorstd::vector::operator<使用它;如果您沒有<調用它是一個錯誤。如果你這樣做,調用它的作品。

更現代的C++會鼓勵SFINAE將其禁用,因此您可以檢測到<是否安全,但是當設計了std::vector時,該技術未被使用。你可以看到這種技術的使用在std::function演變,從貪婪地消耗在通用構造到構造僅被考慮用於重載時,將C++ 11和C++ 14之間的工作,幾乎所有的東西去了。

如果你想SFINAE,你不能依賴於這樣的代碼體。爲了減輕對編譯器的負荷,編譯器只需要檢查聲明沒有做SFINAE測試時的函數的定義。原因

部分原因是,在SFINAE表情是很難;整個身體更難。編譯器必須推測性地編譯函數的主體,點擊錯誤,然後返回「不執行任何操作」狀態。

錯誤在函數的身體總是硬錯誤。你不能在當前版本的C++中避免這種情況。現在

,您可以編寫決定是否會出現錯誤或沒有,但實際上並沒有錯誤,然後用自己的身體,以確定是否有其他代碼會報錯功能。例如:

template<class T> 
auto foo() { 
    constexpr if(sizeof(T)<4) { 
    return std::true_type{}; 
    } else { 
    return std::false_type{}; 
} 

,你可以使用一些SFINAE foo<char>()的地方,它的truefalse -ness可以再拍超載替換失敗與否。

請注意,錯誤(如果有)仍然發生外部函數的主體(foo這裏)。

+1

請注意,委員會的決定很大程度上是因爲一些早期的模板實現完全相反(如果所有模板的成員都爲該實例化工作,實例化只會被編譯),結果工作得很糟糕 - 它阻止了模板的存在在許多現在人們認爲理所當然的情況下實例化的將會很好地工作。舉個例子,'vector'支持移動類型,儘管它明顯包含了使用複製的代碼。 –

相關問題