C++中的表达式SFINAE和硬错误

我很困惑为什么这些函数中的一个会出现硬错误,而另一个不会:

#include <utility>

template <typename ...Args>
auto ffExists1()
-> decltype(ff(std::declval<Args>()...)); // Attempts to see
    // whether you can call ff (which is not defined or declared)
    // with arguments of type Args... This works fine.

template <typename ...Args>
auto ffExists2() -> decltype(&ff); // Gives me a hard error : ff not defined

这是为什么?另外,我该如何ffExists2工作?使用指向函数的指针可以让我确定ffwhile的确切签名,ffExists1只知道我是否可以ff使用类型的参数进行调用Args...

编辑:这是一个ffExists2依赖于模板的版本,导致相同的结果:

#include <utility>

template <typename ...Args>
auto ffExists() -> decltype(ff(std::declval<Args>()...)); //Fine

template <typename ... Args>
void SomeHelperFunc(auto (*) (Args...));

template <typename ...Args>
auto ffExists2() -> decltype(SomeHelperFunc<Args...>(&ff)); // Hard Error

回答

ffExists2,ff不依赖于模板参数,因此它的查找(即通过提供的名称查找函数)是在两阶段查找的第一阶段完成的,即当编译器第一次看到模板时,而不是在模板参数被替换到其中。

正因为如此,即使ff是在这个模板之后定义的,也没关系,因为到那时第一阶段已经完成了。

另一方面,在 中ffExists1, 的查找ff取决于模板参数(因为ADL是此查找的一部分,而 ADL 需要知道参数的类型,即Args...),因此对其的查找推迟到第二阶段,即模板的实例化点,

此时 ADL 检查从模板定义上下文以及模板实例化上下文可见的函数声明,而非 ADL 查找仅检查从模板定义上下文可见的函数声明(换句话说,添加一个新函数模板定义后的声明不会使其可见,除非通过 ADL)。

— (c) cppreference

无法&ff依赖模板参数,也不可能对不依赖模板参数的事物进行 SFINAE 检查。任何对它的尝试都会受到以下因素的阻碍:

[temp.res.general]/6.1

程序格式错误,无需诊断,如果:

— 无法为模板生成有效的专业化...


您可能会认为 C++20requires会有所帮助,因为您可以在没有任何模板的情况下使用它,但是:

[expr.prim.req.general]/5

...

[注 1:如果一个 requires 表达式在其需求中包含无效类型或表达式,并且它没有出现在模板化实体的声明中,那么程序就是格式错误的。— 尾注]

如果将模板参数替换为需求总是会导致替换失败,则程序格式错误;无需诊断。


以上是C++中的表达式SFINAE和硬错误的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>