如何解决C++ 中的表达式 SFINAE 和硬错误 [temp.res.general]/6.1[expr.prim.req.general]/5
我很困惑为什么这些函数中的一个会出现硬错误,而另一个不会:
#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
只知道我是否可以使用 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
不依赖于模板参数,因此对它的查找(即通过提供的名称查找函数)在 two-phase lookup 的第一阶段完成,即当编译器第一次看到模板时,而不是将模板参数替换到模板中时。
因此,即使在此模板之后定义了 ff
,也无所谓,因为第一阶段 is already done by that point。
另一方面,在ffExists1
中,ff
的查找依赖于模板参数(因为ADL是这个查找的一部分,ADL需要知道参数的类型,即 Args...
),所以对它的查找被推迟到第二阶段,即模板的实例化点,
此时 ADL 检查从模板定义上下文以及模板实例化上下文可见的函数声明,而非 ADL 查找仅检查从模板定义上下文可见的函数声明(换句话说,添加模板定义后的新函数声明不会使其可见,除非通过 ADL)。
——(c) cppreference
没有办法让 &ff
依赖于模板参数,也不可能对不依赖于模板参数的事物进行 SFINAE 检查。任何对它的尝试都会受阻:
[temp.res.general]/6.1
程序格式错误,无需诊断,如果:
——不能为模板生成有效的特化...
您可能会认为 C++20 requires
会有所帮助,因为您可以在没有任何模板的情况下使用它,但遗憾的是:
[expr.prim.req.general]/5
...
[注 1:如果 requires 表达式在其需求中包含无效类型或表达式,并且它没有出现在模板化实体的声明中,那么该程序是格式错误的。 — 尾注]
如果将模板参数替换为需求 总是导致替换失败,程序格式错误;不 需要诊断。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。