类模板的嵌套模板参数推导不起作用 [英] Nested template argument deduction for class templates not working

查看:127
本文介绍了类模板的嵌套模板参数推导不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题与解答 中,我编写了一个小包装程序类,该类提供了反向迭代器访问在一定范围内,依赖于类模板的c ++ 1z语言功能模板参数推导( p0091r3 p0512r0

#include <iostream>
#include <iterator>
#include <vector>

template<class Rng>
class Reverse
{
    Rng const& rng;    
public:    
    Reverse(Rng const& r) noexcept
    : 
        rng(r)
    {}

    auto begin() const noexcept { using std::end; return std::make_reverse_iterator(end(rng)); }
    auto end()   const noexcept { using std::begin; return std::make_reverse_iterator(begin(rng)); }
};

int main()
{
    std::vector<int> my_stack;
    my_stack.push_back(1);
    my_stack.push_back(2);
    my_stack.puhs_back(3);

    // prints 3,2,1
    for (auto const& elem : Reverse(my_stack)) {
        std::cout << elem << ',';    
    }
}

但是,执行<$ c $的嵌套应用程序c>反向不产生原始迭代顺序

However, doing a nested application of Reverse does not yield the original iteration order

// still prints 3,2,1 instead of 1,2,3
for (auto const& elem : Reverse(Reverse(my_stack))) {
    std::cout << elem << ',';    
}

实时示例 (对于g ++ 7.0 SVN和clang 5.0 SVN,输出相同)

Live Example (same output for g++ 7.0 SVN and clang 5.0 SVN)

罪魁祸首似乎是类模板的模板参数推论,因为通常的包装器功能确实允许正确的嵌套

The culprit seems to be the template argument deduction for class templates because the usual wrapper function does allow for correct nesting

template<class Rng>
auto MakeReverse(Rng const& rng) { return Reverse<Rng>(rng); }

// prints 1,2,3
for (auto const& elem : MakeReverse(MakeReverse(my_stack))) {
    std::cout << elem << ',';    
}

实时示例 (g ++和clang的输出相同)

Live Example (same output for g++ and clang)

问题:类模板的嵌套模板参数推论是否应该仅在一个级别上起作用?或者这是g ++和clang的当前实现中的错误吗?

Question: is nested template argument deduction for class templates supposed to work only "one level" deep, or is this a bug in the current implementations of both g++ and clang?

推荐答案

Piotr的答案正确地解释了正在发生的事情-move构造函数是一个

Piotr's answer correctly explains what is happening - the move constructor is a better match than your constructor template.

但是(h / t TC 像往常一样)有比只写工厂更好的解决方法:您可以添加一个明确的推导指南来处理包装:

But (h/t T.C. as usual) there's a better fix than just writing a factory anyway: you can add an explicit deduction guide to handle the wrapping:

template <class R>
Reverse(Reverse<R> ) -> Reverse<Reverse<R>>;

由于[over over .match.best]:

The point of this is to override the copy deduction candidate, thanks to the newly added preference in [over.match.best] for this:


鉴于这些定义,一个可行的函数 F1 F1 是从A生成的,则>被定义为比另一个可行函数 F2 更好的函数。扣除指南(13.3.1.8)和 F2 不是。

Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if [...] F1 is generated from a deduction-guide (13.3.1.8) and F2 is not.

因此,我们有四个生成的函数,再次借鉴了Piotr的命名:

Hence, we'd have four generated functions, borrowing again from Piotr's naming:

template <typename Rng>
Reverse<Rng> foo(const Rng& r);             // #1

template <typename Rng>
Reverse<Rng> foo(const Reverse<Rng>& r);    // #2

template <typename Rng>
Reverse<Rng> foo(Reverse<Rng>&& r);         // #3

template <typename Rng>
Reverse<Reverse<Rng>> foo(Reverse<Rng> r);  // #4 - same-ish as #2/3, but deduction guide

之前,#3 被认为是更专业的。现在,首选#4 作为推导指南。因此,我们仍然可以这样写:

Before, #3 was preferred as being more specialized. Now, #4 is preferred as being a deduction guide. So, we can still write:

for (auto const& elem : Reverse(Reverse(my_stack))) {
    std::cout << elem << ',';    
}

可行。

这篇关于类模板的嵌套模板参数推导不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆