此代码是否会导致违反单一定义规则?

Does this code cause a violation of the one-definition rule?

我正在尝试找出在什么情况下以下代码可能会导致违反单一定义规则。

header.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 class 模板的两个不同版本。如果我 link 翻译单元在一起,我是否有 ODR 违规?

很明显 g() 会违反 ODR,因为它在每个翻译单元中都有不同的实现。

但是 f()h() 呢? 每个的实现(即令牌流)将在翻译单元之间保持不变。但它们都隐含地使用了 C 的不同实例化。这有什么区别吗?这里没有名称查找,是吗?

定义为友元声明一部分的函数隐含为内联函数,因此只要所有翻译单元中的所有定义都相同,就不会违反 ODR。它不是它是友元的 class 的成员,而是一个全局函数,类似于将函数声明为友元,然后一旦 class 的定义是,就定义内联函数完成。

这是 h 的情况,它不依赖于任何模板参数,而 f 确实依赖于模板参数,但该参数具有相同的类型(int) 在你的例子中。

函数 g 在 src1.cpp 和 src2.cpp 中有不同的定义,因此这是一个潜在的 ODR 违规。这会导致程序格式错误(无需诊断)如果该函数在两个翻译单元中都使用了 ODR。