【发布时间】:2017-07-03 19:28:03
【问题描述】:
在this Q&A 中,我编写了一个小包装类,它提供对范围的反向迭代器访问,依赖于类模板的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 << ',';
}
}
但是,对Reverse 进行嵌套应用不会产生原始的迭代顺序
// still prints 3,2,1 instead of 1,2,3
for (auto const& elem : Reverse(Reverse(my_stack))) {
std::cout << elem << ',';
}
Live Example(g++ 7.0 SVN 和 clang 5.0 SVN 的输出相同)
罪魁祸首似乎是类模板的模板参数推导,因为通常的包装函数确实允许正确嵌套
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 << ',';
}
Live Example(g++ 和 clang 的输出相同)
问题:类模板的嵌套模板参数推导是否应该只工作“一层”深,或者这是 g++ 和 clang 的当前实现中的一个错误?
【问题讨论】:
-
@cpplearner 我不这么认为,
my_stack是一个命名变量,而引用存储在Reverse对象中,那么这里悬空的是什么? -
但是
Reverse(my_stack)不是一个命名变量,你在Reverse(Reverse(my_stack))中存储了一个对它的引用。 -
@TemplateRex 它不直接绑定到那个引用,所以它在第二个 sn-p 中是 UB,在第一个使用移动构造的地方可能还可以,但总的来说它不是导致行为
-
外部
Reverse的构造函数是复制构造函数,因此使用相同的模板参数。 -
@PiotrSkotnicki 好的,这是有道理的,但仍然令人惊讶。我猜范围包装器仍然需要辅助函数
标签: c++ templates c++17 class-template template-argument-deduction