2013-05-14 124 views
2

考慮以下幾點:單模板實例

/* T.h */ 
template <class T> 
void Too() { 
    std::cout << " Template: " << typeid(T).name() 
       << " size: " << sizeof(T) << std::endl; 
} 
/* A.h */ 
extern void FooA(); 
/* A.cpp */ 
struct Local { 
    int a[2]; 
} 

void FooA() { 
    Local l; 
    std::cout << "<Foo A>:\n" << " Real: " << typeid(l).name() 
       << " size: " << sizeof(l) << std::endl; 
    Too<Local>(); 
} 
​​
/* B.cpp */ 
struct Local { 
    int a[4]; 
}; 

void FooB() { 
    Local l; 
    std::cout << "<Foo B>:\n" << " Real: " << typeid(l).name() \ 
       << " size: " << sizeof(l) << std::endl; 
    Too<Local>(); 
} 
/* main.cpp */ 
int main() { 
    FooA(); 
    FooB(); 
    return 0; 
} 

編譯和運行結果:

<Foo A>: 
    Real: 5Local size: 8 
    Template: 5Local size: 8 
<Foo B>: 
    Real: 5Local size: 16 
    Template: 5Local size: 8 

這意味着,用於這兩個模板調用一個模板實例。值得注意的是 - 第一個。 雖然可以通過定義Too()作爲

template <class T, size_t s = sizeof(T)> Too(); 

我想知道有什麼比較通用的方法對這一問題解決這一「功能」?因爲如果兩個調用結構的大小相同,上面的代碼仍然會失敗。

編輯:

特別是我的問題就在於,我無法改變的文件A和B.所以我可能不會引入匿名命名空間給他們。 有沒有模板方面的解決方案?因此第二個模板參數。

+0

我可能誤解了這一點,但它似乎你打破了一個定義規則,因此得到未定義的行爲。您的程序中有2個不同的結構,稱爲全局名稱空間中的「本地」。 – 2013-05-14 12:54:21

+1

將'struct Local'包裝在一個匿名命名空間中。 – hmjd 2013-05-14 12:55:51

回答

7

您的程序通過包含兩個定義struct Local違反了ODR(一個定義規則)。這意味着它不合格並且具有未定義的行爲,所以任何事情都可能發生。

+0

打我吧,+1 – 2013-05-14 12:54:53

+0

爲什麼我的測試編譯器都沒有提到這個問題? (鏗鏘和MSVC++ 11) – 2013-05-14 13:03:38

+2

您已經顯示出了什麼問題,但沒有回答問題/提供瞭解決方案...... – leemes 2013-05-14 13:06:00

6

正如已經指出的那樣,您違反了One Definition Rule。

你可以在匿名的命名空間中定義的本地結構,讓編譯器知道你在談論不同的地方類型,那麼一切都應該「工作」:

/* A.cpp */ 
namespace { 
    struct Local { 
     int a[2]; 
    } 
} 

/* B.cpp */ 
namespace { 
    struct Local { 
     int a[4]; 
    } 
}