在學習C++泛型編程的時候,是不是非常想知道你實例化的模板函數或模板類在編譯器推導下是什么樣子?今天就給大家簡單介紹一個在線編譯器:C++ Insights (cppinsights.io),它能夠滿足你的需求。
一、常用編譯器的痛點
如下一個代碼示例:
1 template <typename T> 2 T Max(T lhs, T rhs) 3 { 4 return (lhs > rhs) ? lhs : rhs; 5 } 6 7 double Max(double lhs, double rhs) 8 { 9 return (lhs > rhs) ? lhs : rhs; 10 } 11 12 int main() 13 { 14 Max(10.5f, 5.5f); // (1) 15 Max(10.5, 5.5); // (2) 16 system("pause"); 17 }
你用常用編譯器編譯的時候知道第一個Max最終調用的是模板函數還是函數,第二個Max呢?恐怕在編譯期間是不能的,但是在運行的時候通過斷點能夠知道。下面是使用visual studio 2019進行測試。
編譯期間:

運行期間:


第一個Max編譯器選擇函數模板,第二個Max選擇普通的函數。或許同學們會說,這不就行了嗎?
二、泛型編程,真的沒有你想象的那么好學
如下示例:
1 template <typename T1, typename T2> 2 typename std::conditional<(sizeof(Tsizeof(T2)), T1, T2>::type Max1(T1 lhs, T2 rhs) 3 { 4 return (lhs > rhs) ? lhs : rhs; 5 } 6 7 template <typename T1, typename T2> 8 typename std::common_type<T1, T2>::type Max2(T1 lhs, T2 rhs) 9 { 10 return (lhs > rhs) ? lhs : rhs; 11 } 12 13 template <typename T1, typename T2> 14 auto Max3(T1 lhs, T2 rhs) 15 { 16 return (lhs > rhs) ? lhs : rhs; 17 } 18 19 int main() { 20 21 Max1(10.5f, 5.5); 22 Max2(10.5f, 5.5); 23 Max3(10.5f, 5.5); 24 25 return 0; 26 }
你能區分Max1,Max2和Max3的實例化模板函數樣子嗎?(這里不考慮那些對泛型編程很熟的大佬們)。如果模板函數或模板類越來越復雜呢?
三、讓泛型編程變有趣的方法
在學習泛型編程的時候,我在思考有什么辦法看到模板實例化后的代碼,網上搜索了很多相關資料,都沒能找到符合自己需求的方法。這次我終於找到了,它就是cppinsights。
如下實例代碼:
1 template <typename T> 2 class Base 3 { 4 public: 5 void Interface() 6 { 7 auto obj = static_cast<T&>(*this); 8 obj.DoSomething(); 9 } 10 }; 11 12 class D : public Base<D> 13 { 14 public: 15 void DoSomething() 16 { 17 } 18 }; 19 20 int main() 21 { 22 D d; 23 d.Interface(); 24 return 0; 25 }
上面是奇異遞歸模板模式,同學們知道它被實例化后的樣子是什么樣的嗎?下面是使用在線編譯器編譯后的代碼的樣子:
1 template <typename T> 2 class Base 3 { 4 public: 5 void Interface() 6 { 7 auto obj = static_cast<T&>(*this); 8 obj.DoSomething(); 9 } 10 }; 11 12 /* First instantiated from: insights.cpp:14 */ 13 #ifdef INSIGHTS_USE_TEMPLATE 14 template<> 15 class Base<D> 16 { 17 18 public: 19 inline void Interface() 20 { 21 D obj = D(static_cast<D &>(*this)); 22 obj.DoSomething(); 23 } 24 25 // inline constexpr Base() noexcept = default; 26 // inline constexpr Base(const Base<D> &) noexcept = default; 27 }; 28 29 #endif 30 31 32 class D : public Base<D> 33 { 34 35 public: 36 inline void DoSomething() 37 { 38 } 39 40 // inline constexpr D() noexcept = default; 41 // inline constexpr D(const D &) noexcept = default; 42 }; 43 44 45 46 int main() 47 { 48 D d = D(); 49 static_cast<Base<D>&>(d).Interface(); 50 return 0; 51 }
只需要將上面的代碼拷貝到C++ Insights (cppinsights.io)上面點擊編譯,馬上可視化看到實例化的代碼樣子。它是一個開源的項目,GitHub上有其相關的介紹:andreasfertig/cppinsights: C++ Insights - See your source code with the eyes of a compiler (github.com)。它的目的正如它說介紹的那樣:”用編譯器的眼光看你的源代碼“。感興趣的同學可以不妨一試。
參考:
