SFINAE 示例不起作用
SFINAE example not working
我试图弄清楚这个SFINAE概念,我必须说我发现它真的很令人困惑。我理解为什么如果编译器可以根据模板类型/参数推断和选择正确的函数,那将是一个巨大的优势,但我不知道这是否是 SFINAE,因为首字母缩略词所代表的含义意味着否则 IMO。也许你可以为我解决这个问题,但现在这实际上不是我的问题。
我的问题是这样的:我从这里查找并尝试了一个 SFINAE 示例: https://en.cppreference.com/w/cpp/language/sfinae
具体来说,告诉您模板类型 C 是对象类型还是内部类型(int、bool 等(。我正在谈论的示例代码是这样的:
template<typename T>
class is_class {
typedef char yes[1];
typedef char no [2];
template<typename C> static yes& test(int C::*); // selected if C is a class type
template<typename C> static no& test(...); // selected otherwise
public:
static bool const value = sizeof(test<T>(0)) == sizeof(yes);
};
然后我想尝试一下,所以我稍微修改了一下,没有改变任何可能影响将使用哪个函数的内容,最后得到了以下代码。我使用 Visual Studio 2017。我不认为它会C++2017年运行,但它不会落后太多。不用说,它两次显示"不是阶级":
#include<cstdio>
#define say(x) printf(#x "n")
template<typename T>
void f(int T::*) {
printf("f<T>();n");
}
template<class T>
void f(T) {
printf("normal f();n");
}
class Hejsa {
public:
int A;
Hejsa() { A = 2; }
};
template<typename T>
class is_class {
public:
typedef char yes[1];
typedef char no[2];
template<typename C> static yes& test(int C::*) {
say("is class"); return new yes;
}; // selected if C is a class type
template<typename C> static no& test(...) {
say("is not class"); no _n; return _n;
}; // selected otherwise
public:
static bool const value = sizeof(test<T>(0)) == sizeof(yes);
};
int main() {
int var1 = 9;
Hejsa var2;
is_class<Hejsa>::test<Hejsa>(var1);
is_class<Hejsa>::test<Hejsa>(var2);
f(var1);
f(var2);
getchar();
}
是什么原因造成的?你能不能尽量少地改变它,让它"工作",即让test<Hejsa>(var1);
说"不是阶级",test<Hejsa>(var2)
说"是阶级"?("Hejsa"是一个丹麦词,意思是"Hiya"或"你好",类似于;P)
提前感谢,
托马斯
SFINAE 如何创建该特征:
首先,简单的Typedef,以确保不同的尺寸
typedef char yes[1]; // sizeof == 1
typedef char no [2]; // sizeof != 1 (2 actually)
然后,2 个重载函数(声明(:
template<typename C> static yes& test(int C::*);
template<typename C> static no& test(...);
int C::*
是类型int
的成员上的指针。仅当C
是一个类时,它才格式正确(即使该类没有 BTW 类型的int
成员(。对于其他类型(如float
(,它的格式不正确。
...
是接受额外参数(如printf
族(的省略号。
因此,当C
是一个类时,这两个函数都对test<C>(0)
yes& test(int C::* m); // with m = nullptr
no& test(...); // with ... taking int 0
重载解析规则是否选择第一个。(所以返回类型是yes&
(。
但是当C
不是一个类时(比如说一个float
(
对于template<typename C> static yes& test(int C::*);
,通过换人,我们会得到yes& test(int float::*);
由于函数是模板,故障取决于模板, 我们没有错误,而是简单地忽略重载集中的函数(这不是错误(。
只有省略号函数对test<C>(0)
有效(因此返回类型为no&
(。
现在,使用sizeof(test<T>(0))
可以询问编译器它会选择哪个重载(无需调用函数,因此不需要定义(。
我们将最终结果存储在静态杆件is_class::value
中。
一旦你有一个特征,可能的用法包括在重载中或直接SFINAE调度标签:
template <typename T>
std::enable_if_t<is_class<T>::value> foo() { std::cout << "a class"; }
template <typename T>
std::enable_if_t<!is_class<T>::value> foo() { std::cout << "a class"; }
当 bool 为假时,std::enable_if_t<bool>
格式不正确,否则void
替换。
从您的代码中,我会说您将 SFINAE 和重载分辨率混淆了(可能是因为 cppreference.com 示例中同时使用了两者(。
重载解析是编译器用于选择要调用的函数时应用的规则。因此,它允许您根据传递的类型调用不同的函数。
SFINAE 将允许您测试是否可以对您不知道的类型进行操作。通常,测试类型是否具有给定的成员函数。
通常,您将无法编写代码来测试它,因为调用不存在的成员函数是错误的。但是,当应用重载解析规则时,编译器将丢弃一个会导致编译错误的函数。 编译成功是因为省略号重载是一种包罗万象。
现在,SFINAE 的兴趣在于,如果您的类型具有给定的成员函数,编译器将选择更精确的函数(省略号是最后的手段(。使用函数的不同返回类型,可以检测选择了哪个重载。
- 我的神经网络不起作用 [XOR 问题]
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- C++为什么尽管我调用了void函数,它却不起作用
- 为什么在保护模式下继承升级不起作用
- 循环在计数器中不起作用
- 在其他文件中创建类时在 c++ 项目中不起作用
- Visual studio代码重构似乎不起作用(例如,重命名符号-f2)
- SFINAE 示例不起作用
- 为什么void_t在SFINAE中不起作用,但enable_if起作用
- 为什么 SFINAE 在这个简单的成员函数重载中不起作用
- 为什么 SFINAE 在这个例子中不起作用?
- 为什么SFINAE在这种情况下不起作用?
- 为什么SFINAE不起作用?
- SFINAE:检测成员变量的存在在 g++ 上不起作用
- 为什么返回Sfinae转换操作员不起作用
- 构造函数上的SFINAE在VC2017中工作,但在clang / gcc中不起作用
- 请帮助我理解为什么SFINAE在这种情况下不起作用
- 为什么 SFINAE 在默认函数参数的右侧不起作用?
- 尽管使用了模板方法,但SFINAE不起作用