2013-05-14 78 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]; 
    } 
}