c++ 演绎指南和注入的类名

vlf7wbxs  于 2023-02-06  发布在  其他
关注(0)|答案(2)|浏览(122)
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>;

我的问题是,在TIter是两个不同类型并且参数类型仅依赖于Iter的情况下,如何推导类模板参数类型。TIter是独立的,所以从参数推导出Iter不应该暗示X具有X<Iter>类型,对吗?这是书中文字的一些错误还是演绎指南看起来应该和我想的不一样?

wh6knrhe

wh6knrhe1#

你说的对,隐式生成的推演向导确实和你写的那个一样,模板参数推演永远也推演不出T,这确实不会出问题,问题出在用户提供的推演向导上,比如:

template <typename Iter>
X(Iter a, Iter b) -> X<typename Iter::value_type>;

如果注入的类名没有抑制参数推导,那么这个问题可能会造成严重破坏。作者可能忽略了添加推导指南来演示这个问题的必要性。
下面是这个问题的一个例子:

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>,就像它在C14中一样,但是如果类模板参数演绎没有关闭,并且我们添加了演绎指南,我们将得到X<int>
想象一下现有的代码库在迁移到C
17后类型突然改变,那将是非常糟糕的。

eblbsuwk

eblbsuwk2#

我认为作者不必在这里添加任何演绎指南来论证问题,在我看来,我们可以将X<T>::f的定义改写如下:

template <typename Iter>
auto f(Iter b, Iter e){
    X ret(b,e);
    return ret;
}

如果C++在这里没有禁用类模板参数演绎(CTAD),那么这个ret的初始化就是CTAD开始的地方,它会得到类型X<Iter>。在Unslander Monica的例子中,x2会有一个更复杂的类型X<typename std::vector<int>::iterator>。这就是为什么作者没有在演绎指南中详细说明它。

相关问题