2013-06-30 118 views
2

我正在閱讀文章An Idiot's Guide to C++ Templates - Part 2並來到Separation of Declaration and Implementation部分。在頭文件中包含模板實現cpp文件和鏈接混淆

現在我有三個文件及其內容如下:

sample.hpp

#ifndef SAMPLE_HPP 
#define SAMPLE_HPP 

template <typename T> 
void displayValue(T tValue); 

#include "sample.cpp" 

#endif 

sample.cpp的

#include <iostream> 
template <typename T> 
void displayValue(T tValue){ 
    std::cout<<tValue<<std::endl; 
} 

的main.cpp

#include "sample.hpp" 
int main(void) { 
    displayValue(20); 
    displayValue(3.14); 
    return 0; 
} 

據筆者,

項目/現在打造不得添加sample.cpp的編譯過程

但是相反,當我使用:

g++ main.cpp sample.cpp -o main 

它仍然有效!

我認爲在這種情況下,對象sample.o仍然包含NO代碼有關模板功能displayValue,並在main.o對象,它包含的內容。所以理論上沒有錯誤。但爲什麼作者說must not

+0

作者當然不是隻談論gcc,我們也不能說其他編譯器會如何表現。如果你再次鏈接之前鏈接的東西會出現錯誤 –

+0

@MaduraAnushanga是的,我還注意到作者正在使用MSVC編譯器。我只需要確認,如果我們錯誤地將'sample.cpp'添加到編譯文件中並且不會發生鏈接錯誤,那麼就沒有任何危害。如果作者只談論MSVC,那麼我猜這是編譯器的一個缺陷;但我不確定。 –

+1

這取決於你使用的編譯器,作者已經說明了最佳實踐。我更喜歡在頭文件中不包含cpps,您可能剛剛在頭文件中實現了它的功能,但它的工作原理可能會有問題。 –

回答

0

模板是部分定義,因此它們可以被限定爲「部分」實現在標題中。在你的情況,

sample.hpp

#ifndef SAMPLE_HPP 
#define SAMPLE_HPP 

#include <iostream> 
template <typename T> 
void displayValue(T tValue){ 
    std::cout<<tValue<<std::endl; 
} 
#endif 

爲主。CPP

#include "sample.hpp" 
int main(void) { 
    displayValue(20); 
    displayValue(3.14); 
    return 0; 
} 

這將在任何情況下完美地工作,即使你在多個位置添加標題(和非常具有可讀性)

否則你仍然可以讓你做了什麼,是「理論上正確「通過將sample.cpp包含在使用該模板的其他cpp中。這是一個更多的工作。

N.B:這不是問題的確切答案,而是一種繞過所有問題的方法。

1

這是正常的,你沒有得到任何錯誤。因爲你的定義和實現被視爲一個文件。

更好和平常的C++風格是;

頭文件(myClass.h): 您不應該包含實現文件(編譯器會在您找到任何文件時找到它)。 實施(myClass.cpp): 的#include myClass.h

主程序(main.cpp中) 這也將需要的#include myClass.h

如果實現使用這種一貫的風格您只會因爲不應該分開模板函數/類的定義和實現而導致鏈接錯誤。

作者可能指的是這個。

+0

作者在通常的分離案例中說,那裏將會是一個鏈接錯誤,因爲函數模板和聲明的實現在兩個分離的翻譯單元中,並且由於沒有實例化,所以實際上將被丟棄。然後作者說這可以用這種不尋常的方式解決。所以作者對「不得」聲明犯了錯誤?最有可能的是 –

+1

。請注意,預處理器只是將**#include **指令替換爲文件的內容。因此,實際上這種不同尋常的風格,作者正在同一個文件中提供定義和實現。 – sgun