2 回答

TA貢獻1883條經驗 獲得超3個贊
的直接背景基本上是什么,你在模板聲明本身看到的。除此之外的一切都是硬錯誤。硬錯誤示例:
#include <type_traits>template<class T>struct trait{ using type = typename T::type; };template<class T, class U = typename trait<T>::type>void f(int);void f(...);template<class T, class U = typename T::type>void g(int);void g(...);template<class>struct dependent_false : std::false_type{};template<class T>struct X{ static_assert(dependent_false<T>(), "..."); using type = void;};int main(){ f<int>(0); g<X<int>>(0);}

TA貢獻1799條經驗 獲得超6個贊
如果您考慮了確定模板參數替換結果所需的所有模板和隱式定義的函數,并假設它們是在替換開始之前首先生成的,則在第一步中發生的任何錯誤都不會立即出現,并導致硬錯誤。
如果所有這些實例化和隱式定義(可能包括將函數定義為已刪除)都可以正確執行,那么替換期間(即在引用函數模板的實例化模板和隱式定義函數時)會發生任何其他“錯誤”。簽名)不是錯誤,但會導致推理失敗。
因此,給定這樣的功能模板:
template<typename T>voidfunc(typename T::type* arg);
以及在其他功能的推論失敗時將使用的“后備”:
template<typename>voidfunc(...);
和這樣的類模板:
template<typename T> struct A { typedef T* type; };
調用func<A<int&>>(nullptr)
將替代A<int&>
,T
并且為了檢查是否T::type
存在,必須實例化A<int&>
。如果我們設想在調用之前放一個顯式實例化func<A<int&>(nullptr)
:
template class A<int&>;
那么這將失敗,因為它嘗試創建類型int&*
并且不允許使用指向引用的指針。我們沒有到檢查替換是否成功的地步,因為實例化存在一個嚴重的錯誤A<int&>
。
現在,我們有一個明確的專業化A
:
template<> struct A<char> { };
對的調用func<A<char>>(nullptr)
需要實例化A<char>
,因此請想象在調用之前程序中某個地方的顯式實例化:
template class A<char>;
此實例化還可以,沒有任何錯誤,因此我們繼續進行參數替換。work的實例化A<char>
,但A<char>::type
不存在,但是可以,因為它僅在的聲明中引用func
,因此只會導致參數推導失敗,而...
將調用后備功能。
在其他情況下,替換可能導致特殊成員函數被隱式定義(可能已刪除),這可能會觸發其他實例化或隱式定義。如果在“生成實例和隱式定義”階段發生錯誤,那么它們就是錯誤,但是如果成功但在替換期間發生錯誤,則函數模板簽名中的表達式將變為無效,例如,因為它使用的成員不存在或被隱式定義為刪除的東西,這不是錯誤,只是推論失敗。
因此,我使用的思維模型是,替換需要首先執行“準備”步驟才能生成類型和成員,這可能會導致嚴重錯誤,但是一旦我們完成了所有必要的生成,任何進一步的無效使用就不會出錯。當然,這一切都是將問題從“ 即時上下文是什么意思?” 移開。“在檢查此替換之前需要生成哪些類型和成員?” 因此它可能會或可能不會幫助您!
- 2 回答
- 0 關注
- 768 瀏覽
添加回答
舉報