Facebook的Folly库有一个UninitializedMemoryHacks
标头,它使用一些非传统的技术来访问类的私有成员。它似乎类似于2010 UninitializedMemoryHacks
中描述的方法。
我试图了解如果从多个翻译单元使用blog post by Johannes Schaub是否会导致违反一个定义规则。这个问题特别涉及使用resizeWithoutInitialization
function,以在每个翻译单元中生成不同的模板实例。
我将有问题的代码简化为以下最小示例:
header.h
resizeWithoutInitialization
src1.cpp
tag struct declared inside an anonymous namespace
src2.cpp
#pragma once
template<typename T, typename U>
class C {
friend int f() {
// Uses the template parameter that doesn't change
return sizeof(T);
}
friend int g() {
// Uses the template parameter that does change
return sizeof(U);
}
friend int h() {
// Does not refer to template parameters
return 0;
}
};
// Declarations to help name lookup
int f();
int g();
int h();
我已经在两个不同的翻译单元中实例化了#include "header.h"
// Cause definintion of f(), g() and h()
template class C<int, double>;
类模板的两个不同版本。如果我将翻译单元链接在一起,是否会违反ODR?
[显然,#include "header.h"
// Cause definintion of f(), g() and h()
template class C<int, float>;
会违反ODR,因为在每个翻译单元中都有不同的实现。
但是C
和g()
呢?每个翻译单元之间的实现(即令牌流)将保持不变。但是它们都隐式地使用f()
的不同实例。这有什么区别吗?没有名称查找发生在这里吗?
[我相信Folly库使用h()
的变体,因为C
朋友函数从不实际引用其所在类的f()
模板参数。
如果要使用多个翻译单元的detail::unsafeStringSetLargerSize
的FollyMemoryDetailTranslationUnitTag
变体,会构成对ODR的侵犯吗?
定义为好友声明一部分的函数隐式为内联函数,因此只要所有定义在所有翻译单元中都相同,就不会违反ODR。它不是类的成员,而是它的朋友,而是全局函数,类似于将函数声明为朋友,然后在类的定义完成后定义内联函数。
string
的情况不依赖于任何模板参数,folly::resizeWithoutInitialization
的情况不依赖于模板参数,但是在您的示例中,该参数具有相同的类型(h
)。 >
函数f
在src1.cpp和src2.cpp中具有不同的定义,因此这可能是违反ODR的行为。这导致程序格式错误(无需诊断)。[[if