clang`llvm::trailing_objects_internal::TrailingObjectsImpl<8,
clang::TemplateParameterList, llvm::TrailingObjects,
clang`llvm::trailing_objects_internal::TrailingObjectsImpl<8,
clang::TemplateParameterList, llvm::TrailingObjects,
clang`llvm::trailing_objects_internal::TrailingObjectsImpl<8,
clang::TemplateParameterList, llvm::TrailingObjects,
clang`std::__1::enable_if::Foo, llvm::TrailingObjects::Foo
>::value, unsigned long>::type
: public TrailingObjectsBase
这是最后一层基类,它从TrailingObjectsBase继承
static constexpr size_t additionalSizeToAllocImpl(size_t
SizeSoFar) {
return SizeSoFar;
}
当最后一个类型的时候,它直接返回SizeSoFar.没有后续的类了。
template
static constexpr
std::enable_if_t<</span>
std::is_same, Foo>::value,
size_t>
totalSizeToAlloc(typename
trailing_objects_internal::ExtractSecondType<</span>
TrailingTys, size_t>::type... Counts)
{
return sizeof(BaseTy) +
ParentType::additionalSizeToAllocImpl(0, Counts...);
}
和
template
static constexpr
std::enable_if_t<</span>
std::is_same, Foo>::value,
size_t>
additionalSizeToAlloc(typename
trailing_objects_internal::ExtractSecondType<</span>
TrailingTys, size_t>::type... Counts)
{
return ParentType::additionalSizeToAllocImpl(0,
Counts...);
}
也很有意思,它通过
std::enable_if_t<</span>
std::is_same, Foo>::value,
size_t>判断是不是和定义的类型一样,来确定size_t。
否则应该报错了。
typename
trailing_objects_internal::ExtractSecondType<</span>
TrailingTys, size_t>::type...
Counts
这个模板类方法,用来返回相同个数的size_t对像。
totalSizeToAlloc = sizeof(BaseTy) +
ParentType::additionalSizeToAllocImpl(0, Counts...);
additionalSizeToAlloc =
ParentType::additionalSizeToAllocImpl(0, Counts...);
这样一层一层统计。最后就会到了上面一个参数的TrailingObjectsBase。
最后来说一下。
Expr** exprTemp = getTrailingObjects();
我特地加了一个第二个模板参数来调,这个代码我加的,只为调试这个类的工作方式。
/// Returns a pointer to the trailing object array of the
given type
/// (which must be one of those specified in the class
template). The
/// array may have zero or more elements in it.
template T *getTrailingObjects() {
verifyTrailingObjectsAssertions();
// Forwards to an impl function with overloads, since
member
// function templates can't be specialized.
return this->getTrailingObjectsImpl(
static_cast(this),
TrailingObjectsBase::OverloadToken());
}
它会调
static NextTy *
getTrailingObjectsImpl(BaseTy *Obj,
TrailingObjectsBase::OverloadToken) {
auto *Ptr =
TopTrailingObj::getTrailingObjectsImpl(
Obj, TrailingObjectsBase::OverloadToken()) +
TopTrailingObj::callNumTrailingObjects(
Obj, TrailingObjectsBase::OverloadToken());
if (requiresRealignment())
return reinterpret_cast(alignAddr(Ptr,
Align::Of()));
else
return reinterpret_cast(Ptr);
}
可以看到
TrailingObjectsBase::OverloadToken(),这个是用来判断把这个方法实现成不同的override,如果传一个不存在的类,应该会报错。
它会得前一个类型指针,加上前一个类型对像的个数。
它是调用TopTrailingObj也就是本类的不同重载。得的时候就是从后向前推导类型和分配时候从前到后调用不同类型不一样。
static BaseTy *
getTrailingObjectsImpl(BaseTy *Obj,
TrailingObjectsBase::OverloadToken) {
return Obj;
}
// callNumTrailingObjects simply calls numTrailingObjects on
the
// provided Obj -- except when the type being queried is
BaseTy
// itself. There is always only one of the base object, so that
case
// is handled here. (An additional benefit of indirecting
through
// this function is that consumers only say
"friend
// TrailingObjects", and thus, only this class
itself can call the
// numTrailingObjects function.)
static size_t
callNumTrailingObjects(const BaseTy *Obj,
TrailingObjectsBase::OverloadToken) {
return 1;
}
template
static size_t callNumTrailingObjects(const BaseTy *Obj,
TrailingObjectsBase::OverloadToken) {
return
Obj->numTrailingObjects(TrailingObjectsBase::OverloadToken());
}
它最后会进到基类为参数,getTrailingObjectsImpl(BaseTy *Obj,
TrailingObjectsBase::OverloadToken)的重载,直接返回指针,它的个数永远是1,+1相当于加了sizeof(BaseTy).
而其他对象时候,则会调用callNumTrailingObjects的其他类型的模板方法。
调用numTrailingObjects的对应版本,而这个通常是在最终类中实现的。神吧。
TemplateParameterList(const ASTContext& C,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc, ArrayRef Params,
SourceLocation RAngleLoc, Expr
*RequiresClause);
size_t numTrailingObjects(OverloadToken) const {
return NumParams;
}
size_t numTrailingObjects(OverloadToken) const {
return HasRequiresClause ? 1 : 0;
}
现在原理分析完了,来验证一下call stack.
frame #0:
0x0000000105a4f068
clang`llvm::TrailingObjects
clang::NamedDecl*,
clang::Expr*>::getTrailingObjectsImpl(Obj=0x000000012d019b68,
(null)=OverloadToken @ 0x000000032fdaafc8) at
TrailingObjects.h:249:12
frame #1:
0x0000000105a4f035
clang`llvm::trailing_objects_internal::TrailingObjectsImpl<8,
clang::TemplateParameterList, llvm::TrailingObjects,
clang::TemplateParameterList,
clang::NamedDecl*,
clang::Expr*>::getTrailingObjectsImpl(Obj=0x000000012d019b68,
(null)=OverloadToken @ 0x000000032fdab008) at
TrailingObjects.h:162:17
frame #2:
0x0000000105a4f0c5
clang`llvm::trailing_objects_internal::TrailingObjectsImpl<8,
clang::TemplateParameterList, llvm::TrailingObjects,
clang::NamedDecl*,
clang::Expr*>::getTrailingObjectsImpl(Obj=0x000000012d019b68,
(null)=OverloadToken @ 0x000000032fdab048) at
TrailingObjects.h:162:17
frame #3:
0x0000000105a4f0a2
clang`clang::Expr**
llvm::TrailingObjects::getTrailingObjects(this=0x000000012d019b68)
at TrailingObjects.h:301:12
得Expr*地址,也就是先得到BaseTy* + 1个对像+ sizeof(NamedDecl*) *
NumParams
传第一个参数的情况
frame #0:
0x0000000105a4f068
clang`llvm::TrailingObjects::getTrailingObjectsImpl(Obj=0x000000012d01d768,
(null)=OverloadToken @ 0x000000032fdaafe8) at
TrailingObjects.h:249:12
frame #1:
0x0000000105a4f035
clang`llvm::trailing_objects_internal::TrailingObjectsImpl<8,
clang::TemplateParameterList, llvm::TrailingObjects,
clang::TemplateParameterList,
clang::NamedDecl*,
clang::Expr*>::getTrailingObjectsImpl(Obj=0x000000012d01d768,
(null)=OverloadToken @ 0x000000032fdab028) at
TrailingObjects.h:162:17
frame #2:
0x0000000105a4f002
clang`clang::NamedDecl**
llvm::TrailingObjects::getTrailingObjects(this=0x000000012d01d768)
at TrailingObjects.h:301:12
LLVM源码阅读之四---TrailingObjects
LLVM源码阅读之四 --- TrailingObjects
今天来研究一下这个类TrailingObjects,这也是奇葩的类。
class TemplateParameterList final
: private llvm::TrailingObjects
Expr *>
第一,它必须被别人私有继承,然后Derived类会被当成第一个模板参数传递给TrailingObjects模板类。
这是一个CRTP的模板,奇异递归模板模式。Curiously Recurring Template Pattern。
它会把子类的类型传递给模板基类,然后在基类实现时,直接static_cast来调用方法。
可以参考https://blog.csdn.net/sinat_21107433/article/details/123145236
template
class TrailingObjects : private trailing_objects_internal::TrailingObjectsImpl<</p>
trailing_objects_internal::AlignmentCalcHelper<</p>
TrailingTys...>::Alignment,
BaseTy, TrailingObjects,
BaseTy, TrailingTys...>
它从TrailingObjectsImpl继承。其中BaseTy类是Derived子类。然后TrailingObjectsImpl同样是个CRTP模板。
把自己传进去,然后又把类型传一遍。
template class AlignmentCalcHelper {
private:
enum {
FirstAlignment = alignof(First),
RestAlignment = AlignmentCalcHelper::Alignment,
};
public:
enum {
Alignment = FirstAlignment > RestAlignment ? FirstAlignment : RestAlignment
};
};
template class AlignmentCalcHelper {
public:
enum { Alignment = alignof(First) };
};
用来计算alignment,这个在创建对象时候用。
template
typename NextTy, typename... MoreTys>
class TrailingObjectsImpl
MoreTys...>
: public TrailingObjectsImpl
MoreTys...>
它会从
frame #0:
0x000000010a960928
clang`llvm::trailing_objects_internal::TrailingObjectsImpl<8, clang::TemplateParameterList, llvm::TrailingObjects,
clang::Expr*>::additionalSizeToAllocImpl(SizeSoFar=8) at TrailingObjects.h:199:12
frame #1:
0x000000010a960914
clang`llvm::trailing_objects_internal::TrailingObjectsImpl<8, clang::TemplateParameterList, llvm::TrailingObjects,
clang::NamedDecl*,
clang::Expr*>::additionalSizeToAllocImpl(SizeSoFar=8, Count1=0) at TrailingObjects.h:179:12
frame #2:
0x000000010a9608dc
clang`llvm::trailing_objects_internal::TrailingObjectsImpl<8, clang::TemplateParameterList, llvm::TrailingObjects,
clang::TemplateParameterList,
clang::NamedDecl*,
clang::Expr*>::additionalSizeToAllocImpl(SizeSoFar=0, Count1=1, MoreCounts=0) at TrailingObjects.h:179:12
frame #3:
0x000000010a957de4
clang`std::__1::enable_if::Foo, llvm::TrailingObjects::Foo >::value, unsigned long>::type
llvm::TrailingObjects::totalSizeToAlloc(Counts=1, Counts=0) at TrailingObjects.h:328:29
frame #4: 0x000000010a957d44 clang`clang::TemplateParameterList::Create(C=0x000000013380f800, TemplateLoc=(ID = 14342), LAngleLoc=(ID = 14350), Params=ArrayRef @ 0x000000032fdab200, RAngleLoc=(ID = 14361), RequiresClause=0x0000000000000000) at DeclTemplate.cpp:123:26
从调用栈上看,很明显它一层层继承
clang::TemplateParameterList,
clang::NamedDecl*,
clang::Expr*
到
clang::NamedDecl*,
clang::Expr*
再到
clang::Expr*
逐渐去掉前面的Base类。
// The base case of the TrailingObjectsImpl inheritance recursion,
// when there's no more trailing types.
template
class alignas(Align) TrailingObjectsImpl
: public TrailingObjectsBase
这是最后一层基类,它从TrailingObjectsBase继承
static constexpr size_t additionalSizeToAllocImpl(size_t SizeSoFar) {
return SizeSoFar;
}
当最后一个类型的时候,它直接返回SizeSoFar.没有后续的类了。
template
static constexpr std::enable_if_t<</span>
std::is_same, Foo>::value, size_t>
totalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType<</span>
TrailingTys, size_t>::type... Counts) {
return sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(0, Counts...);
}
和
template
static constexpr std::enable_if_t<</span>
std::is_same, Foo>::value, size_t>
additionalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType<</span>
TrailingTys, size_t>::type... Counts) {
return ParentType::additionalSizeToAllocImpl(0, Counts...);
}
也很有意思,它通过
std::enable_if_t<</span>
std::is_same, Foo>::value, size_t>判断是不是和定义的类型一样,来确定size_t。
否则应该报错了。
typename trailing_objects_internal::ExtractSecondType<</span>
TrailingTys, size_t>::type... Counts
这个模板类方法,用来返回相同个数的size_t对像。
totalSizeToAlloc = sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(0, Counts...);
additionalSizeToAlloc = ParentType::additionalSizeToAllocImpl(0, Counts...);
这样一层一层统计。最后就会到了上面一个参数的TrailingObjectsBase。
最后来说一下。
Expr** exprTemp = getTrailingObjects();
我特地加了一个第二个模板参数来调,这个代码我加的,只为调试这个类的工作方式。
/// Returns a pointer to the trailing object array of the given type
/// (which must be one of those specified in the class template). The
/// array may have zero or more elements in it.
template T *getTrailingObjects() {
verifyTrailingObjectsAssertions();
// Forwards to an impl function with overloads, since member
// function templates can't be specialized.
return this->getTrailingObjectsImpl(
static_cast(this), TrailingObjectsBase::OverloadToken());
}
它会调
static NextTy *
getTrailingObjectsImpl(BaseTy *Obj,
TrailingObjectsBase::OverloadToken) {
auto *Ptr = TopTrailingObj::getTrailingObjectsImpl(
Obj, TrailingObjectsBase::OverloadToken()) +
TopTrailingObj::callNumTrailingObjects(
Obj, TrailingObjectsBase::OverloadToken());
if (requiresRealignment())
return reinterpret_cast(alignAddr(Ptr, Align::Of()));
else
return reinterpret_cast(Ptr);
}
可以看到
TrailingObjectsBase::OverloadToken(),这个是用来判断把这个方法实现成不同的override,如果传一个不存在的类,应该会报错。
它会得前一个类型指针,加上前一个类型对像的个数。
它是调用TopTrailingObj也就是本类的不同重载。得的时候就是从后向前推导类型和分配时候从前到后调用不同类型不一样。
static BaseTy *
getTrailingObjectsImpl(BaseTy *Obj,
TrailingObjectsBase::OverloadToken) {
return Obj;
}
// callNumTrailingObjects simply calls numTrailingObjects on the
// provided Obj -- except when the type being queried is BaseTy
// itself. There is always only one of the base object, so that case
// is handled here. (An additional benefit of indirecting through
// this function is that consumers only say "friend
// TrailingObjects", and thus, only this class itself can call the
// numTrailingObjects function.)
static size_t
callNumTrailingObjects(const BaseTy *Obj,
TrailingObjectsBase::OverloadToken) {
return 1;
}
template
static size_t callNumTrailingObjects(const BaseTy *Obj,
TrailingObjectsBase::OverloadToken) {
return Obj->numTrailingObjects(TrailingObjectsBase::OverloadToken());
}
它最后会进到基类为参数,getTrailingObjectsImpl(BaseTy *Obj,
TrailingObjectsBase::OverloadToken)的重载,直接返回指针,它的个数永远是1,+1相当于加了sizeof(BaseTy).
而其他对象时候,则会调用callNumTrailingObjects的其他类型的模板方法。
调用numTrailingObjects的对应版本,而这个通常是在最终类中实现的。神吧。
TemplateParameterList(const ASTContext& C, SourceLocation TemplateLoc,
SourceLocation LAngleLoc, ArrayRef Params,
SourceLocation RAngleLoc, Expr *RequiresClause);
size_t numTrailingObjects(OverloadToken) const {
return NumParams;
}
size_t numTrailingObjects(OverloadToken) const {
return HasRequiresClause ? 1 : 0;
}
现在原理分析完了,来验证一下call stack.
frame #0:
0x0000000105a4f068
clang`llvm::TrailingObjects
clang::NamedDecl*,
clang::Expr*>::getTrailingObjectsImpl(Obj=0x000000012d019b68, (null)=OverloadToken @ 0x000000032fdaafc8) at TrailingObjects.h:249:12
frame #1:
0x0000000105a4f035
clang`llvm::trailing_objects_internal::TrailingObjectsImpl<8, clang::TemplateParameterList, llvm::TrailingObjects,
clang::TemplateParameterList,
clang::NamedDecl*,
clang::Expr*>::getTrailingObjectsImpl(Obj=0x000000012d019b68, (null)=OverloadToken @ 0x000000032fdab008) at TrailingObjects.h:162:17
frame #2:
0x0000000105a4f0c5
clang`llvm::trailing_objects_internal::TrailingObjectsImpl<8, clang::TemplateParameterList, llvm::TrailingObjects,
clang::NamedDecl*,
clang::Expr*>::getTrailingObjectsImpl(Obj=0x000000012d019b68, (null)=OverloadToken @ 0x000000032fdab048) at TrailingObjects.h:162:17
frame #3:
0x0000000105a4f0a2
clang`clang::Expr** llvm::TrailingObjects::getTrailingObjects(this=0x000000012d019b68) at TrailingObjects.h:301:12
得Expr*地址,也就是先得到BaseTy* + 1个对像+ sizeof(NamedDecl*) * NumParams
传第一个参数的情况
frame #0:
0x0000000105a4f068
clang`llvm::TrailingObjects::getTrailingObjectsImpl(Obj=0x000000012d01d768, (null)=OverloadToken @ 0x000000032fdaafe8) at TrailingObjects.h:249:12
frame #1:
0x0000000105a4f035
clang`llvm::trailing_objects_internal::TrailingObjectsImpl<8, clang::TemplateParameterList, llvm::TrailingObjects,
clang::TemplateParameterList,
clang::NamedDecl*,
clang::Expr*>::getTrailingObjectsImpl(Obj=0x000000012d01d768, (null)=OverloadToken @ 0x000000032fdab028) at TrailingObjects.h:162:17
frame #2:
0x0000000105a4f002
clang`clang::NamedDecl**
llvm::TrailingObjects::getTrailingObjects(this=0x000000012d01d768) at TrailingObjects.h:301:12