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

Expression SFINAE and hard errors in c++

我很困惑为什么其中一个函数给出了硬错误,而另一个却没有:

#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 工作?使用指向函数的指针可以让我确定 ff 的确切签名,而 ffExists1 只能确定我是否可以使用 Args....[=18 类型的参数调用 ff =]

编辑:这里是 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 不依赖于模板参数,因此对它的查找(即通过提供的名称查找函数)在 [=23= 的第一阶段完成],即当编译器第一次看到模板时,而不是模板参数被替换到其中时。

因此,即使ff定义在这个模板之后,也没关系,因为第一阶段is already done by that point.

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

at which time ADL examines function declarations that are visible from the template definition context as well as in the template instantiation context, while non-ADL lookup only examines function declarations that are visible from the template definition context (in other words, adding a new function declaration after template definition does not make it visible except via ADL).

— (c) cppreference

无法使 &ff 依赖于模板参数,并且无法对不依赖于模板参数的事物执行 SFINAE 检查。任何尝试都会被挫败:

[temp.res.general]/6.1

The program is ill-formed, no diagnostic required, if:

— no valid specialization can be generated for a template ...


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

[expr.prim.req.general]/5

...

[Note 1: If a requires-expression contains invalid types or expressions in its requirements, and it does not appear within the declaration of a templated entity, then the program is ill-formed. — end note]

If the substitution of template arguments into a requirement would always result in a substitution failure, the program is ill-formed; no diagnostic required.