Lỗi thường gặp của các newbie khi mới động đến Template trong C++

Trong bài này mình không giải thích Template function, Template class trong C++ là gì mà mình sẽ đề cập đến một lỗi build/compile chương trình mà các newbie hay gặp phải khi mới làm quen với Template, tất nhiên là cả cách giải quyết lỗi đó như thế nào nữa.

LỖI mà mình muốn đề cập đến ở đây là lỗi Linking chương trình, khi đó trình biên dịch sẽ báo là không tìm thấy implement (định nghĩa) của các hàm thành viên của Template class trong khi rõ ràng đã có definition trong file source *.cpp rồi. Nhiều anh em mới (ngày xưa mình cũng vậy) không thể hiểu nổi tại sao và lại phải lóc cóc lên google dạo một vòng. Cuối cùng thì cũng xử lý được thôi nhưng nếu hiểu trước thì vẫn hơn, đỡ mất time search gg, có khi lại support được thằng khác lấy le nữa 😁.

Khuyến các ae nào chưa nắm vững về việc một chương trình được biên dịch như thế nào thì xem lại bài này ⇒ Source code C++ được biên dịch như thế nào


Giả sử bạn có template class SampleTemplateClass như sau

  • Khai báo trong file header SampleTemplateClass.h
  • Định nghĩa trong file implementation SampleTemplateClass.cpp

Ok, bây giờ bạn sử dụng class này trong main.cpp. Cách làm thông thường chúng ta vẫn làm là gì ? Đúng bài là include SampleTemplateClass.h vào rồi xài thôi, quá easy →

Biên dịch chương trình phát nào …

ĐÙ. Lỗi linking cmnr. Thông báo lỗi này là mình build trên VS2015, trên các trình biên dịch hoặc IDE khác thì lỗi có thể báo không giống y câu chữ nhưng cũng sẽ tương tự như trên. Đại để là compiler nó chửi, nó bảo tao dell tìm thấy định nghĩa mấy cái hàm của class SampleTemplateClass với T là int ở đâu cả.


TẠI SAO LỖI ?

Về bản chất template trong C++ sẽ cung cấp một khuôn mẫu hàm hoặc lớp (class) chứ chưa cung cấp implementation cụ thể cho từng kiểu dữ liệu. Implementation cụ thể cho từng kiểu dữ liệu được sử dụng với template trong chương trình sẽ được compiler tạo ra trong quá trình biên dịch.

Ở đây, file main.cpp chỉ include file header của SampleTemplateClass nên khi compile file main.cpp trong đó có sử dụng template SampleTemplateClass với kiểu dữ liệu cụ thể là int thì compiler không tìm thấy template thân hàm của các hàm thành viên như constructor, destructor, setX, printX nên trong file main.obj (là file được biên dịch từ main.cpp) sẽ không có implementation các hàm của SampleTemplateClass<int>. Trong khi đó SampleTemplateClass.cpp thì cũng chỉ có template chứ ko chứa implementation của bất cứ kiểu dữ liệu cụ thể nào nên khi linking các file object lại với nhau để tạo thành file executable thì mới xảy ra lỗi “unresolved external symbol”.


GIẢI PHÁP LÀ GÌ ?

Dưới đây mình sẽ chia sẻ 2 cách mà mình biết để giải quyết lỗi này.

*** Cách 1:  include cả file .h và .cpp của template class khi sử dụng

Cụ thể trong trường hợp này thì thêm #include “SampleTemplateClass.cpp” vào file main.cpp như sau →

*** Cách 2:  move toàn bộ nội dung trong file .cpp của template class sang file .h của nó

Trong trường hợp class SampleTemplateClass ở đây thì SampleTemplateClass.h sẽ bao gồm cả phần khai báo và định nghĩa của template. File SampleTemplateClass.cpp không cần thiết nữa và ta sẽ xóa luôn nó đi.

Đây là cách mà các template class chuẩn (STL  – Standard Template Class) của C++ như map, vector, list, etc… vẫn dùng nên mình cũng thích cách này hơn.


Chúc các bạn enjoy CODING !

— Phạm Minh Tuấn (Shun) —