gpt4 book ai didi

c++ - SFINAE 示例不起作用

转载 作者:行者123 更新时间:2023-11-28 01:32:28 24 4
gpt4 key购买 nike

我正在尝试弄清楚这个 SFINAE 概念,但我必须说我发现它真的很令人困惑。我理解为什么如果编译器可以根据模板类型/args 推断并选择正确的函数,那将是一个巨大的优势,但我不知道那是否是 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”是一个丹麦语词,意思是“你好”或“你好”之类的意思;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 时它才是良构的是一个类(即使该类没有 int BTW 类型的成员)。对于其他类型(如 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"; }

std::enable_if_t<bool>当 bool 为假时格式错误,并被 void 替代否则。

关于c++ - SFINAE 示例不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50891078/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com