为什么模板参数推导在这里不起作用?

29
我创建了两个简单的函数,这些函数获取模板参数和一个定义类型的空结构体。
//S<T>::type results in T&
template <class T>
struct S
{
    typedef typename T& type;
};

//Example 1: get one parameter by reference and return it by value
template <class A>
A
temp(typename S<A>::type a1)
{
    return a1;
}

//Example 2: get two parameters by reference, perform the sum and return it
template <class A, class B>
B
temp2(typename S<A>::type a1, B a2)//typename struct S<B>::type a2)
{
    return a1 + a2;
}

参数类型应用于结构体S以获得引用。我使用一些整数值调用它们,但编译器无法推断参数。
int main()
{
    char c=6;
    int d=7;
    int res = temp(c);
    int res2 = temp2(d,7);
}

错误1 错误C2783:'A temp(S::type)':无法推断出'A'的模板参数 错误2 错误C2783:'B temp2(S::type,B)':无法推断出'A'的模板参数
为什么会发生这种情况?难道看不出模板参数是charint值吗?
3个回答

31
作为第一条注释,当您提到一个依赖名称时,使用typename名称。因此,在这里您不需要它。

template <class T>
struct S
{
    typedef T& type;
};

关于模板实例化,问题在于typename S<A>::type表征了A的一个非推导上下文。当一个模板参数仅在非推导上下文中使用时(对于你的函数中的A情况),它不会被考虑用于模板参数推导。详见C++标准(2003)第14.8.2.4节。
为使你的调用起作用,你需要显式指定类型:

temp<char>(c);

8

这似乎是一个未推导的上下文。根据C ++标准14.8.2.4/4:

未推导的上下文包括:

  • 被使用限定符指定的类型的嵌套名称限定符
  • 模板参数引用表达式的一个或多个模板参数时,是一个模板ID的类型。

当以包含未推导上下文的方式指定类型名称时,构成该类型名称的所有类型也都是未推导的。但是,复合类型可以同时包括推导和未推导类型。[示例:如果将类型指定为A<T>::B<T2>,则TT2均为未推导的。同样,如果将类型指定为A<I+J>::X<T>,则IJT均为未推导的。如果将类型指定为void f(typename A<T>::B, A<T>),则A<T>::B中的T是未推导的,但A<T>中的T是推导的。]


1
你能否用简单的语言和例子来解释一下这个问题:“使用限定符标识符指定的类型的嵌套名称限定符。”我知道嵌套名称限定符是 X<T>::,而限定标识符则是以 :: 作为前缀的标识符,但我无法得出结论或理解整个问题。非常感谢 :) - Mr.Anubis
是指使用限定符ID指定的类型的嵌套名称限定符,还是指使用限定符ID指定的嵌套名称限定符的类型。 - Mr.Anubis

5

推理是向前方向进行的:

template <class T> void f(T);

f(2); // can deduce int from T

为什么会发生这种情况?

反向操作无法正常工作(参考你的示例):

template <class A> void g(typename S<A>::type);

看到模板参数是char和int类型的值,难道这很难理解吗?

模板推导可以实现一些神奇的(图灵完备的)功能,但我不认为这是其中之一。

你可以尝试使用以下代码(未经测试):

template <class SA> void h(SA a1)
{
    STATIC_ASSERT(same_type<SA, S<A>::type>::value);
    typedef typename SA::type A;

    ...
}

使用您喜欢的静态断言库(Boost有两个)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接