这个has_member类模板如何工作? [英] How does this has_member class template work?
问题描述
我想了解以下类模板的工作原理(摘自 here ),但我不能正确理解:
typename类型>
class has_member
{
class yes {char m;};
class no {yes m [2];};
struct BaseMixin
{
void operator()(){}
};
struct Base:public Type,public BaseMixin {};
template< typename T,T t> class Helper {};
template< typename U>
static no deduce(U *,Helper< void(BaseMixin :: *)(),& U :: operator()> * = 0);
static yes deduce(...);
public:
static const bool result = sizeof(yes)== sizeof(deduce((Base *)(0)));
};
更具体地说,我不明白 BaseMixin
和 operator()
的存在。此外,由于 Base
是从它派生的,我不太明白。
更具体地说,当模板参数 无论如何,这是我的测试代码: 输出( ideone ): 关于第二个项目符号的标准引文。 C ++ 11§10.2/ 2-6: 2以下步骤定义成员名的查询结果 3在类范围 Type
定义 operator c $ c>,为什么仅,那么SFINAE被触发,导致第一个
deduce()
函数被忽略, / p>
struct A {}; // SFINAE被触发为A
struct B {void operator()(){}}; //没有为B触发SFINAE
struct C {void operator()(int,int){}}; //没有为C
触发SFINAE c main()
{
std :: cout< std :: boolalpha; //启用true / false而不是1/0!
std :: cout<< has_member< A> :: result<< std :: endl;
std :: cout<< has_member< B> :: result<< std :: endl;
std :: cout<< has_member< C> :: result<< std :: endl;
}
false
true
true
BaseMixin
有一个运算符()
定义。
c $ c>源于
类型
和 BaseMixin
,因此如果类型
有一个运算符()
然后在上的名称查找Base :: operator()
对于 Base *
,而不是调用
。
deduce
*
助手< void(BaseMixin :: *)(),& U :: operator()> code>只会实例化
& U :: operator()
明确解析为 BaseMixin :: operator()
。
Helper< void(BaseMixin :: *)(),& U :: operator()>
不会实例化,因为类型
有自己的 operator()
查找& U :: operator()
不明确,因此重载
返回类型<$ c $
f
C
C
中的 f
>,由两个组件集组成:声明集,一组名为 f
的成员;和子对象集,一组子对象,其中找到这些成员的声明(可能包括 using-declaration )。在声明集中, use-declaration 将被它们指定的成员替换,类型声明(包括注入类名)将被它们指定的类型替换。 S(f,C)计算如下:
4如果 C
一个声明 f
,声明集包含 C中声明的
,它满足查找发生的语言结构的要求。 [注意:例如,在阐述型类型说明符或基本说明符中查找名称将忽略所有非类型声明,而在 nested-name-specifier 中查找名称时会忽略函数,变量和枚举器声明。作为另一示例,在使用声明中查找名称包括类或枚举的声明,该类或枚举通常被同一范围中的该名称的另一声明隐藏。 — end note ]如果生成的声明集不为空,子对象集包含 f
C
本身,计算完成。
5否则(即 C
不包含 f
或生成的声明集为空), S(f,C)最初为空。 如果 C
有基类,则在每个直接基类子对象中计算 f
并将每个这样的查找集合S(f,B i )依次合并为S(f ,C)。
6以下步骤定义合并查找结果: (f,B i )的子对象成员中的至少一个的基本类子对象是S(f,C) / em>,或者如果S(f,B )是空的,则 S(f,C) 。相反,如果S(f,C)的子对象成员中的每一个是S(f,B)的子对象成员中的至少一个的基类子对象, sub>),或者如果 S(f,C)为空,则新的 S(f,C) 否则,如果声明集合)和 S(f,C)不同,则合并是不明确的:新的 S(f,C)在随后的合并中,无效的声明集被认为与任何其他声明集不同。 I'm trying to understand how the following class template works (taken from here), but I couldn't understand it properly: More specifically, I don't understand the purpose of Even more specifically, when template parameter Anyway, this is my test code: Output(ideone):
Standard citation regarding the second bullet — C++11 §10.2/2-6: 2 The following steps define the result of name lookup for a member name 3 The lookup set for 4 If 5 Otherwise (i.e., 6 The following steps define the result of merging lookup set S(f,Bi) into the intermediate S(f,C):
这篇关于这个has_member类模板如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
template <typename Type>
class has_member
{
class yes { char m;};
class no { yes m[2];};
struct BaseMixin
{
void operator()(){}
};
struct Base : public Type, public BaseMixin {};
template <typename T, T t> class Helper{};
template <typename U>
static no deduce(U*, Helper<void (BaseMixin::*)(), &U::operator()>* = 0);
static yes deduce(...);
public:
static const bool result = sizeof(yes) == sizeof(deduce((Base*)(0)));
};
BaseMixin
and the presence of operator()
in it. Also, since Base
is derived from it, I don't understand it as well. Type
has defined operator()
, why only then SFINAE is triggered, causing the first deduce()
function to be ignored and the second one is chosen?
struct A{}; //SFINAE is triggered for A
struct B{ void operator()(){} }; //SFINAE is not triggered for B
struct C{ void operator()(int,int){} }; //SFINAE is not triggered for C
int main()
{
std::cout << std::boolalpha; //enable true/false instead of 1/0!
std::cout << has_member<A>::result << std::endl;
std::cout << has_member<B>::result << std::endl;
std::cout << has_member<C>::result << std::endl;
}
false
true
true
BaseMixin
has an operator()
definition.Base
derives from both Type
and BaseMixin
, so if Type
has an operator()
then name lookup on Base::operator()
will be ambiguous.deduce
is called for Base*
, not Type*
.Helper<void (BaseMixin::*)(), &U::operator()>
will only instantiate if &U::operator()
unambiguously resolves to BaseMixin::operator()
.Helper<void (BaseMixin::*)(), &U::operator()>
does not instantiate, it's because Type
has its own operator()
making name lookup on &U::operator()
ambiguous, and consequently the overload of deduce
returning type yes
is chosen.
f
in a class scope C
.f
in C
, called S(f,C), consists of two component sets: the declaration set, a set of members named f
; and the subobject set, a set of subobjects where declarations of these members (possibly including using-declarations) were found. In the declaration set, using-declarations are replaced by the members they designate, and type declarations (including injected-class-names) are replaced by the types they designate. S(f,C) is calculated as follows:C
contains a declaration of the name f
, the declaration set contains every declaration of f
declared in C
that satisfies the requirements of the language construct in which the lookup occurs. [ Note: Looking up a name in an elaborated-type-specifier or base-specifier, for instance, ignores all non-type declarations, while looking up a name in a nested-name-specifier ignores function, variable, and enumerator declarations. As another example, looking up a name in a using-declaration includes the declaration of a class or enumeration that would ordinarily be hidden by another declaration of that name in the same scope. —end note ] If the resulting declaration set is not empty, the subobject set contains C
itself, and calculation is complete.C
does not contain a declaration of f
or the resulting declaration set is empty), S(f,C) is initially empty. If C
has base classes, calculate the lookup set for f
in each direct base class subobject Bi, and merge each such lookup set S(f,Bi) in turn into S(f,C).