多个翻译单元是否可以使用不同的默认模板参数但相同的定义具有相同模板的声明?例如,如果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<>
答案 0 :(得分:5)
这取决于。默认参数不更改模板的定义,它是相同的。但它确实改变了使用模板的东西的定义,因为它们没有提供任何参数。
考虑:
// 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规则。