首页 > 解决方案 > 此代码是否会导致违反单一定义规则?

问题描述

我试图弄清楚在什么情况下以下代码可能会导致违反单一定义规则。

头文件.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 违规?

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

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

标签: c++templatesfriendfriend-functionone-definition-rule

解决方案


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

就是这种情况 for h,它不依赖于任何模板参数,以及 for f,它依赖于模板参数,但该参数int在您的示例中具有相同的类型 ( )。

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


推荐阅读