我试图弄清楚以下代码在什么情况下可能会违反一个定义规则。
页眉.h
#pragma once
#include <cstddef>
template<typename T, typename U>
class C {
friend std::size_t f() {
// Uses the template parameter that doesn't change
return sizeof(T);
}
friend std::size_t g() {
// Uses the template parameter that does change
return sizeof(U);
}
friend std::size_t h() {
// Does not refer to template parameters
return 0;
}
};
// Declarations to help name lookup
std::size_t f();
std::size_t g();
std::size_t h();
src1.cpp
#include "header.h"
// Cause definintion of f(), g() and h()
template class C<int, double>;
src2.cpp
#include "header.h"
// Cause definintion of f(), g() and h()
template class C<int, float>;
我已经在两个不同的翻译单元中显式实例化了C
类模板的两个不同版本。如果我将翻译单元链接在一起,我是否存在ODR违规行为?
g()
显然会违反ODR,因为它在每个翻译单元中都有不同的实现。
但是f()
和h()
呢?每个的实现(即令牌流(在翻译单元之间将保持不变。但它们都隐含地使用了C
的不同实例化。这有什么不同吗?这里没有名字查询,是吗?
定义为友元声明一部分的函数隐式地是内联函数,因此只要所有翻译单元中的所有定义都相同,就不存在ODR冲突。它不是它的朋友类的成员,而是一个全局函数,类似于将函数声明为朋友,然后在类的定义完成后定义内联函数。
h
不依赖于任何模板参数,而f
依赖于模板参数,但该参数在您的示例中具有相同的类型(int
(。
函数g
在src1.cpp和src2.cpp中有不同的定义,因此这是潜在的ODR冲突。如果函数在两个翻译单元中都使用ODR,则会导致程序格式错误(无需诊断(。