template <typename T>
struct has_xxx {
private:
using true_type = char;
using false_type = long;
template <typename C>
static true_type has_xxx_impl(decltype(&C::xxx)); // comment 1
template <typename C>
static false_type has_xxx_impl(...); // comment 2
public:
enum { value = sizeof(has_xxx_impl<T>(0)) == sizeof(true_type) }; // comment3
};
struct Foo { int xxx() {return 0;}; };
struct Foo2 {};
int main() {
static_assert(has_xxx<Foo>::value, "");
}
这是一个检测结构是否具有某种方法的结构。 我对代码有一些疑问。
答案 0 :(得分:1)
以下说明不完善,不引用标准。我尽力解释它是可以理解的。
has_xxx_impl(decltype(&C::xxx))
接受由decltype(&C::xxx)
生成的类型
&C::xxx
是指向成员的指针,decltype(&C::xxx)
是其类型。
另一个has_xxx_impl(...)
接受“任何”
所以,当你有has_xxx_impl<T>
编译器必须选择时,上面的一个。它更喜欢更好的匹配。因此,当类型包含xxx
时,第一个匹配比...
版本更好。如果它不包含这样的成员,则无法选择该函数,并且必须使用另一个函数(...
)
感谢SFINAE
- 替换失败(尝试传递不存在的成员类型时)不会产生错误(选择其他重载)
请注意,两个函数都返回不同的类型(true_type
和false_type
,这些类型被定义为具有不同的大小),因此使用sizeof(has_xxx_impl<T>(0)) == sizeof(true_type)
可以判断选择了哪一个。此比较的结果设置为value
,您可以从外部访问。
答案 1 :(得分:1)
在评论1中,这个'&amp; C'是什么意思,为什么我不能只写'C :: xxx'
&
实际上是指xxx
的{{1}}部分。也就是说,在&C::xxx
中获取成员xxx
的地址(希望是一个函数,而不是静态成员 - 稍后会更多)
在评论2中,参数'...'是什么意思,它是参数包,还是代表任何类型的参数
C
或省略号运算符是variadic argument,它接受任何内容。这是一种非常C风格的做事方式,通常不是很安全的。今天你最常见的地方是吞咽异常:
...
(注意:这不是参数包,也不是折叠表达式的一部分。请参阅§5.2.2/ 6)
在评论3中,has_xxx_impl(0)如何工作? T被Foo取代,那么参数0怎么样?为什么选择第一个函数?
try{
ThrowableFunctionCall();
} catch(...) // swallow any exceptions
{}
是一种使用overload resolution将值设置为sizeof(has_xxx_impl<T>(0)) == sizeof(true_type)
或true_type
的聪明方式。请允许我解释一下:
首先调用false_type
会使其显示为
has_xxx_impl<T>
是否可行,因为它们具有相同的名称,并且可能都可以使用类型template <typename C>
static true_type has_xxx_impl(decltype(&C::xxx)); // comment 1
template <typename C>
static false_type has_xxx_impl(...); // comment 2
进行实例化。然而
T
尝试创建指向成员类型的指针(例如,decltype(&C::xxx)
表示成员函数指针),并且它是在类型推导的上下文中这样做的。如果声明格式不正确,那么SFINAE生效并使其成为一个糟糕的候选人,只留下
int(C::*)()
由于template <typename C>
static false_type has_xxx_impl(...); // comment 2
匹配任何内容,因此该值设置为...
或false_type
。
如果语句格式正确,则可以将long
正确分配给函数指针类型(它不情愿地转换为具有0
值的指针类型)。此转换优先于匹配null
(try it yourself!),因此值...
为true_type
。
最后,
char
我们可以说是将value = sizeof(has_xxx_impl<T>(0)) == sizeof(true_type)
的大小与char
的大小进行比较(没有long
个案例)
或者大小为xxx
,大小为long
(有long
个案例。)
请注意,在C ++ 11/14中完全没有必要这样做,如果xxx
是成员变量而不是函数,则确实会失败:
xxx
melak47的评论虽然更简单,却有类似的垮台。
更好的解决方案是使用struct Foo3{static const int xxx;};
类型特征:
is_member_function_pointer