在模板化函数中输入`T :: some_typredef`的推断

时间:2011-07-06 08:53:58

标签: c++ templates

给定模板函数,不直接使用模板参数进行输入。 C ++类型推断如何工作?比如给出

template<typename T>
void f(T::value_type){}

何时(如果有的话)将为此函数键入推理工作?

template<typename T1,...>void f(T1,T2,...)之外是否还有其他可能发生类型推断的地方?

与往常一样,引用额外信用标准。

4 个答案:

答案 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>,则TT2都不受限制。同样,如果某个类型指定为A<I+J>::X<T>,则IJT不会被限制。如果将类型指定为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 argumentsthis)有时需要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)