我认为基于标准,f
实际上是不依赖的。
14.6.2.2 类型相关的表达式 [temp.dep.expr]
3 一个id 表达式是依赖于类型的,如果它包含
- 一个标识符,通过名称查找与使用依赖类型声明的一个或多个声明相关联,
这同样适用于全局模板函数,就像它适用于成员模板函数一样:一点也不。的返回类型U
取决于模板函数的定义,但对于调用者来说,函数类型f<int>
已经从 转换U(U)
为int(int)
。无论如何,它不能解释为什么编译器会以不同的方式处理这两种情况,也不能解释为什么非模板成员函数也被视为依赖。
- 一个依赖的模板ID,
- 指定依赖类型的转换函数 ID,或
这些不适用。在template-id中没有<
or>
必须始终存在,并且没有调用转换函数。
- 命名未知专业化成员的嵌套名称说明符或限定 ID ;
见下文。
T
或者,如果它为某些T
(14.5.1.3)命名了具有“未知边界数组”类型的当前实例化的静态数据成员。
这也不适用:不涉及数组。
所以这取决于是否f
是未知专业的成员。但它不是:
14.6.2.1 依赖类型 [temp.dep.type]
5 一个名字是一个未知专业的成员,如果它是
- 一个合格的ID,其中[...]。
- 一个合格的ID,其中[...]。
- 一个id 表达式,表示类成员访问表达式 (5.2.5) 中的成员,其中 [...].
这些不能应用:f
既不是限定的,也不是类成员访问表达式的一部分。
由于唯一f
可以依赖的方法是如果它是未知专业化的成员,并且它不是未知专业化的成员,则f
一定不能依赖。
至于为什么编译器仍然将其视为依赖,我没有答案。我的答案的某些部分是错误的,编译器有错误,或者编译器遵循不同版本的 C++ 标准。使用一个不管名称是否依赖都可以工作的示例进行测试显示了编译器处理的一些变化:
#include <cstdio>
void f(const char *s, ...) { std::printf("%s: non-dependent\n", s); }
struct S1 { };
template <typename T>
struct S2 {
static S1 a;
static S1 b() { return {}; }
template <typename U>
static U c() { return {}; }
static void z() {
f("S1()", S1()); // sanity check: clearly non-dependent
f("T()", T()); // sanity check: clearly dependent
f("a", a); // compiler agreement: non-dependent
f("b()", b()); // compiler disagreement: dependent according to GCC 4.8, non-dependent according to clang
f("c<T>()", c<T>()); // sanity check: clearly dependent
f("c<S1>()", c<S1>()); // compiler agreement: dependent
f("decltype(b())()", decltype(b())()); // compiler agreement: dependent
}
};
void f(const char *s, S1) { std::printf("%s: dependent\n", s); }
// Just to show it's possible to specialize the members
// without specializing the full template.
template <>
S1 S2<S1>::b() { return {}; }
template <>
template <>
S1 S2<S1>::c<S1>() { return {}; }
int main() {
S2<S1>::z();
}
b()
clang 处理,decltype(b())()
和的这种差异c<S1>()
对我来说尤其令人不安。这没有任何意义。他们显然都同样依赖。我可以从实现的角度理解,必须注意不要为成员函数生成代码,因为可能有S2<S1>::b
or的特殊化S2<S1>::c<S1>
,但这适用于所有,并且对返回类型没有影响。