SFINAE C++方法检查

3

我正在努力理解SFINAE。

我们正在使用它来检查一个类是否有一个名为“Passengers”的方法。

根据一些在线示例,我们构建了以下模板类:

#ifndef TYPECHECK
#define TYPECHECK

#include "../Engine/carriage.h"

namespace TSS{

template<typename T>
class has_passengers{
private:
    typedef char one;
    typedef struct{char a[2];} two;

    template<typename C> static one test( decltype(&C::Passengers) );
    template<typename C> static two test(...);
public:
    static bool const value = sizeof(test<T>(0)) == sizeof(one);
};

template<typename T>
struct CarriageTypeCheck{
    static_assert(has_passengers<T>::value, "Train initialized with illegal carriage");
};

}


#endif // TYPECHECK

我明白了两种测试方法中的任意一种是如何被选择的,但我不理解以下行为什么要将test<T>初始化为0:

    static bool const value = sizeof(test<T>(0)) == sizeof(one);

我看不出0对于检查的重要性。 另外,为什么要使用decltype?


你没有检查类是否有成员函数 Passengers。你正在检查它是否有成员 Passengers,这可能是一个函数,但不一定是。 - krzaq
好的观点!谢谢! - Benjamin Larsen
2个回答

2
第一个重载函数(可能)以类方法的指针作为参数。由于C ++从C继承,值0可以转换为NULL指针或nullptr。因此,如果SFINAE没有排除第一个重载函数,则test<T>(0)成为有效的函数调用,其sizeof等于sizeof(one)。否则,这将解析为第二个重载函数调用。
至于为什么使用decltype的简短答案:否则它将不是有效的C ++。在函数声明中,函数的参数必须是类型,指定函数参数的类型。&C :: Passengers 不是类型(在其预期用途的上下文中),因此这将不是有效的C ++。 decltype()自动获取其参数的类型,使其成为有效的C ++。

好的。但是如果T没有Passengers,那么它不就等于'sizeof(two)'了吗?那么调用将会是test(nullpointer),大小将会是2? - Benjamin Larsen
@BenjaminLarsen 如果 T 没有乘客,类型推断将会失败,函数模板将被忽略;这就是 SFINAE 的工作原理。对于这种情况,没有传递空指针的规则,如果没有 SFINAE,你将会得到一个编译错误。 - songyuanyao
我现在明白了!谢谢大家。 - Benjamin Larsen

1
由于`0`可以作为两种情况(即两个重载的`test`函数)的参数,因此对于成员指针(视为空指针)和可变参数`...`都是有效的,所以我无法看出`0`的重要性。
另外一个问题是 - 为什么要使用`decltype`?
`decltype`用于描述成员指针(即`&C::Passengers`)作为`test`函数的参数时的类型。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接