问题 模板别名如何影响模板参数扣除?


在C ++ 03中,模板参数推导在某些上下文中不会发生。例如:

template <typename T> struct B {};

template <typename T>
struct A
{
    typedef B<T> type;
};

template <typename T>
void f(typename A<T>::type);

int main()
{
    B<int> b;
    f(b);  // ERROR: no match
}

这里, int 不推断 T,因为嵌套类型如 A<T>::type 是一个非推断的上下文。

我是否写过这样的函数:

template <typename T> struct B {};

template <typename T>
void f(B<T>);

int main()
{
    B<int> b;
    f(b);
}

一切都很好,因为 B<T>   推断的背景。

但是,在C ++ 11中,模板别名可用于以类似于第二个示例的语法伪装嵌套类型。例如:

template <typename T> struct B {};

template <typename T>
struct A
{
    typedef B<T> type;
};

template <typename T>
using C = typename A<T>::type;

template <typename T>
void f(C<T>);

int main()
{
    B<int> b;
    f(b);
}

模板参数推导会在这种情况下起作用吗?换句话说,模板别名是推导的上下文还是非推导的上下文?或者他们是否继承了别名的推导/非推断状态?


2204
2018-01-08 03:39


起源

别名只是别名。这就像写作 template <typename T> void f(typename A<T>::type);,这是不可扣除的。 - Kerrek SB
可能重复 C ++,模板参数不能推导出来 - Nawaz
我认为Kerrek SB对此是正确的。如果提供了报价,我就不需要去搜索一个;-) - Dietmar Kühl
@Nawaz:我不认为它是重复的:这是关于模板别名的,我在你指出的问题中看不到任何模板别名的提示。 - Dietmar Kühl
@Nawaz:请在重复之前先阅读问题... - HighCommander4


答案:


换句话说,模板别名是推导的上下文还是非推导的上下文?

它们与等效代码一样可以在不使用模板别名的情况下进行推导。例如

template<typename T>
using ref = T&;

template<typename T>
void f(ref<T> r);

现在你可以打电话了 f(x) 和 T 将被推断完美。在定义时间 f 已经, ref<T> 被类型取代 T&。和 T& 是推断的背景。

在你的情况下 C<T> 被替换为 typename A<T>::type,这是一个非推断的上下文 T所以 T 无法推断。


8
2018-01-08 10:49



约翰内斯的优秀答案中的关键词是“在 定义时间 的 f 已经“(强调我的)。很容易错过,但知道它解释了一切。 - Dave Abrahams


想象一下:

template <typename T> struct Foo { typedef   T type; }
template <> struct Foo<char>     { typedef int type; }

template <typename T> using mytype = typename Foo<T>::type;

template <typename T> void f(mytype<T>);

现在,如果我想 int n; f(n);,我怎么能决定我是否想要 T = int 要么 T = char?整个问题不受模板别名的影响,是您无法推断出来的 向后 所有可能定义的东西。


1
2018-01-08 03:48





我认为C ++标准中的相关引用是14.5.7 [temp.alias]第2段:

当template-id引用别名模板的特化时,它等同于通过替换别名模板的type-id中的template-parameters的template-arguments获得的关联类型。 [注意:永远不会推导出别名模板名称。 - 结束说明]

引用后面有一个例子,它有效地说明在函数模板中使用别名模板并希望推导出模板参数是没有意义的。即使对于不涉及嵌套类型的情况,这显然也适用。


1
2018-01-08 04:04



你的上一个陈述不正确。关于演绎的引用是什么,不能推断出别名模板名称。那是 template<template<typename T> class C> void f(C<T>); ref<int> r; f(r);是不可能推断出来的 C == ref (鉴于我的定义 ref 在我的回答中)。这并不意味着你的结论意味着什么。 - Johannes Schaub - litb
好的,我可以接受这个。然而,昨天我没有找到更好的报价(但我可能已经被混淆了)。你能指点我的标准报价吗? - Dietmar Kühl
你自己引用了它。模板ID ref<T> 相当于 T& 通过你给出的报价。因此,非规范性的说明表明它无法推断 ref。但它可用于演绎 T,因为这个早期更换。看到的解决方案 open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#395 和 stackoverflow.com/a/6623089/34509 - Johannes Schaub - litb
我明白了 - 非常感谢你! - Dietmar Kühl