多个翻译单元是否可以具有具有不同默认模板参数但定义相同的同一模板的声明? 例如,如果 b.cpp
和 c.cpp
中的翻译单元链接在一起,以下代码是否违反 ODR?
// a.hpp
template <bool> class x {...};
// b.cpp
template <bool = true> class x;
#include "a.hpp"
// uses of x<>
// c.cpp
template <bool = false> class x;
#include "a.hpp"
// uses of x<>
这取决于。默认参数不会更改模板的定义,它是相同的。但它确实改变了使用模板的事物的定义,因为它们不提供参数。
考虑:
// d.hpp
struct Broken {
x<> member;
};
以及该标头的用法:
template <bool = true> class x;
#include "d.hpp"
// use Broken
template <bool = false> class x;
#include "d.hpp"
// Use Broken
现在您的程序违反了 ODR,因为一个翻译单元将Broken
视为包含x<true>
,而另一个翻译单元将Broken
视为包含x<false>
。
更简单更安全的方法是在.cpp中声明一个常量,并且不要修改模板:
// b.cpp
#include "a.hpp" // no default argument
const bool default = true;
// any use of x<> becomes x<default> in the rest of the code
// similarly for c.cpp
模板的定义在所有翻译单元中都是相同的,并且您会得到一些类似于您想要的效果。请注意,default
具有内部链接,因此不同的default
对象不会导致违反 ODR。
与以前一样,此处适用相同的警告,如果您替换Broken
的定义以使用default
,并且该值在不同的翻译单元中定义为不同,则仍然会违反 ODR 规则。