给定模板函数,不直接使用模板参数进行输入。 C ++类型推断如何工作?比如给出
template<typename T>
void f(T::value_type){}
何时(如果有的话)将为此函数键入推理工作?
除template<typename T1,...>void f(T1,T2,...)
之外是否还有其他可能发生类型推断的地方?
与往常一样,引用额外信用标准。
答案 0 :(得分:6)
它永远不适用于嵌套类型,除非T也是参数。
如果你打电话给f(1)
,编译器就没有机会找到嵌套typedef int value_type;
的所有T。
您可以推断出属于参数类型的类型,例如
template<class T>
void f(std::vector<T>);
答案 1 :(得分:5)
我想这是你的答案:
14.8.2.4 - 从类型[temp.deduct.type]
中扣除模板参数[...]
-3 - [...]
在大多数情况下,用于撰写
P
的类型,模板和非类型值参与模板参数推断。也就是说,它们可用于确定模板参数的值,并且如此确定的值必须与其他地方确定的值一致。但是,在某些上下文中,该值不参与类型推导,而是使用模板参数的值,这些参数可以在别处推导或明确指定。如果模板参数仅在非弱化上下文中使用且未明确指定,则模板参数推断将失败。-4 - 非弱化的上下文是:
使用 qualified-id 指定的类型的嵌套名称说明符。
template-id 的类型,其中一个或多个 template-arguments 是一个引用模板参数的表达式
如果以包含非弱化上下文的方式指定类型名称,则包含该类型名称的所有类型也不会受到限制。但是,复合类型可以包括推导类型和非推导类型。 [示例:如果类型指定为
A<T>::B<T2>
,则T
和T2
都不受限制。同样,如果某个类型指定为A<I+J>::X<T>
,则I
,J
和T
不会被限制。如果将类型指定为void f(A<T>::B, A<T>)
,则T
中的A<T>::B
未受到限制,但推导出T
中的A<T>
。 ]
您的T::value_type
是类型的 qualified-id ,因此 nested-name-specifier 中的类型是非限制性的,必须明确指定。< / p>
修改:此信息来自ISO/IEC 14882:1998。
答案 2 :(得分:0)
标准要求您消除依赖类型的歧义:
template<typename T>
void f(typename T::value_type){}
过去在这个领域有一些不太标准的行为,导致代码编译在一个(MSVC)而不是另一个(GCC)编译器。这些天,很可能在像Boost这样的通用标准库的影响下,编译器似乎只接受正确的代码。
disambiguate identifiers dependent on template arguments(this)有时需要typename关键字。可以这样想:你必须给编译器足够的信息,以便在解析模板定义时第一次完成语法检查。当时不知道实际的模板参数(C ++有一个涉及的语法)你必须给编译器提示一个令牌将在后面代表什么样的符号
答案 3 :(得分:0)
除非您以某种方式指定T
参数,否则编译器不会尝试以任何方式扣除T
。
即使你明确指定它,我相信它只会在提供原始定义的地方工作,而不是typedef。
考虑以下示例(使用clang ++编译,显然g ++失败):
#include <stdio.h>
template <typename T>
void foo(T) {
printf("foo(T)\n");
}
template <typename T>
void foo(typename T::value) {
printf("foo(T::value)\n");
}
struct X {
class value {};
};
struct Z {
typedef int value;
};
struct XZ {
typedef Z value;
};
typedef X::value Xv;
#define CALL(function,param) printf(#function " (" #param ") = "); function(param());
void explicitCalls() {
printf("Explicit calls:\n");
CALL(foo<int>,int);
CALL(foo<X::value>,X::value);
CALL(foo<Z::value>,Z::value);
CALL(foo<XZ::value>,XZ::value);
CALL(foo<Xv>,Xv);
}
void implicitCalls() {
printf("Implicit calls:\n");
CALL(foo,int);
CALL(foo,X::value);
CALL(foo,Z::value);
CALL(foo,XZ::value);
CALL(foo,Xv);
}
int main() {
explicitCalls();
implicitCalls();
}
输出结果为:
Explicit calls:
foo<int> (int) = foo(T)
foo<X::value> (X::value) = foo(T::value)
foo<Z::value> (Z::value) = foo(T)
foo<XZ::value> (XZ::value) = foo(T)
foo<Xv> (Xv) = foo(T::value)
Implicit calls:
foo (int) = foo(T)
foo (X::value) = foo(T)
foo (Z::value) = foo(T)
foo (XZ::value) = foo(T)
foo (Xv) = foo(T)