template <typename T>
struct X
{
template <typename Iter>
X(Iter a, Iter b) {}
template <typename Iter>
auto f(Iter a, Iter b)
{
return X(a, b);
}
};
在“C++模板,完整指南”第2版中,前面有一个例子是关于注入类名的隐式演绎向导的字幕,作者提到对于注入的类名禁用类参数演绎,因为隐式演绎向导会导致f的返回类型为X<Iter>
。但是我相信模板构造函数的隐式推导指南应该看起来像下面这样。
template <typename T, typename Iter>
X(Iter a, Iter b) -> X<T>;
我的问题是,在T
和Iter
是两个不同类型并且参数类型仅依赖于Iter
的情况下,如何推导类模板参数类型。T
和Iter
是独立的,所以从参数推导出Iter
不应该暗示X
具有X<Iter>
类型,对吗?这是书中文字的一些错误还是演绎指南看起来应该和我想的不一样?
2条答案
按热度按时间wh6knrhe1#
你说的对,隐式生成的推演向导确实和你写的那个一样,模板参数推演永远也推演不出
T
,这确实不会出问题,问题出在用户提供的推演向导上,比如:如果注入的类名没有抑制参数推导,那么这个问题可能会造成严重破坏。作者可能忽略了添加推导指南来演示这个问题的必要性。
下面是这个问题的一个例子:
x2
的类型是什么?如果我们读取类模板定义,我们期望它是X<float>
,就像它在C14中一样,但是如果类模板参数演绎没有关闭,并且我们添加了演绎指南,我们将得到X<int>
!想象一下现有的代码库在迁移到C17后类型突然改变,那将是非常糟糕的。
eblbsuwk2#
我认为作者不必在这里添加任何演绎指南来论证问题,在我看来,我们可以将
X<T>::f
的定义改写如下:如果C++在这里没有禁用类模板参数演绎(CTAD),那么这个ret的初始化就是CTAD开始的地方,它会得到类型
X<Iter>
。在Unslander Monica的例子中,x2
会有一个更复杂的类型X<typename std::vector<int>::iterator>
。这就是为什么作者没有在演绎指南中详细说明它。