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 ++模板,完整指南” 第二版中,有一个先前的示例,该示例涉及带有注入类名的隐式演绎指南的字幕。作者提到对于注入的类名禁用类参数推论,因为由于隐式推论指南,f返回的类型为X<Iter>
。但是我相信模板构造函数的隐式推导指南看起来像下面的指南。
template <typename T, typename Iter>
X(Iter a, Iter b) -> X<T>;
我的问题是,在这种情况下,T
和Iter
是两个截然不同的类型,而参数类型仅依赖于Iter
,如何推导类模板参数类型。同样,即使可以以某种方式推导T,T
和Iter
是独立的,所以从参数推论Iter
并不意味着X
的类型为X<Iter>
吗?书中的文字是否有此错误,还是推导指南看起来与我的想法有所不同?
答案 0 :(得分:5)
您是正确的。隐式生成的推导指南确实看起来就像您编写的那样。模板参数推论永远无法从中推论T
。确实不会造成任何问题。问题出在用户提供的扣除指南上。像这样:
template <typename Iter>
X(Iter a, Iter b) -> X<typename Iter::value_type>;
Which are often added to allow class template argument deduction from iterators。如果注入的类名不抑制自变量推导,那可能会造成严重破坏。作者可能忽略了添加该演绎指南以演示该问题的需要。
以下是问题的说明:
auto v = std::vector<int>{1, 2};
auto x1 = X<float>(begin(v), end(v));
auto x2 = x1.f(begin(v), begin(v));
x2
是什么类型?如果我们阅读了类模板定义,我们期望它是X<float>
,就像在C ++ 14中一样,但是如果没有关闭类模板参数推导并且添加推论指南,我们将得到X<int>
!
想象一下现有的代码库,其中的类型在移至C ++ 17之后突然转变。那将是非常糟糕的。