[英]Template instantiation decltype & declval with std::tuple_cat
如果我对std::tuple_cat
进行完整,合格的调用,则以下代码将与MSVC,GCC和Clang进行std::tuple_cat
。 但是如果我对tuple_cat
进行非限定调用, tuple_cat
不会在任何这些编译器上编译...即使我正在using namespace std;
!
如果我调用函数不合格,那么所有三个编译器都会找到正确的函数 - 但是抱怨std::tuple<void>
实例化std::tuple<void>
。
为什么这很重要? 这不应该没有区别吗?
#include <tuple>
auto Test() {
using A = std::tuple<void>;
using B = std::tuple<void>;
using namespace std;
using AB = decltype(
#ifdef QUALIFIED
std::
#endif
tuple_cat(std::declval<A>(), std::declval<B>())
);
AB* ptr = nullptr;
return ptr;
}
见演示 。
实例化tuple<void>
是不正确的,但只是命名它不是。 这里的区别恰好归结为一个需要完全实例化的情况,另一个只需要查看模板参数。
当您对std::tuple_cat
进行完全限定的调用时,名称查找只会在命名空间std
找到名为tuple_cat
的内容。 这将是一些函数模板,它需要一堆tuple
并找出如何连接它们的参数。 理解这个函数模板的返回类型的任何部分实际上都不需要在任何地方进行实例化。
但是当你对tuple_cat
进行无条件调用时,我们有两种不同的查找方式:
定期不合格的查找 - 由于你using namespace std;
它最终完成了与上面相同的操作using namespace std;
- 它会找到std::tuple_cat
并且最终能够确定“正确”的答案(对于允许tuple<void>
开始的权利的某些定义)。
参数依赖查找。 ADL要求我们查看所有相关的命名空间和来自我们的参数的其他函数。 这些包括“隐藏的朋友” - 在类的主体内定义的friend
函数。 要知道是否有任何隐藏的朋友,我们需要完全实例化这些类型 - 而且就此而言,我们遇到了错误,一切都爆发了。
这个ADL步骤必须发生 - 在我们执行该步骤之前,我们不会知道std::tuple_cat
是唯一的tuple_cat
。
隐藏的朋友是什么的例子:
template <typename T>
int foo(T) { return 42; }
template <typename T>
struct A {
friend bool foo(A) { return true; } // this is a hidden friend
};
using R = decltype(foo(declval<A<int>>()));
为了确定R
是什么,我们需要实例化A<int>
以查看它是否有任何隐藏的朋友 - 它确实如此,这就是我们为R
获得bool
的方式。 如果我们对foo
进行了合格的调用,我们就会得到int
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.