【问题标题】:When does && mean 'forwarding reference'?&& 什么时候表示“转发参考”?
【发布时间】:2016-12-20 19:44:06
【问题描述】:

编译时,以下代码导致此错误:

'Container::Wrapper::Wrapper(S)': 成员函数已经 定义或声明

编译器是否认为Wrapper的构造函数中的S&&是转发引用?

template<typename T>
struct Container
{
    template<class S>
    struct Wrapper {
        S obj;
        Wrapper(S&& obj) : obj(std::forward<S>(obj)){}
        Wrapper(const S& obj) : obj(obj){}
    };

    template<class S>
    void push_back(S&& obj) {
        void *storage = malloc(sizeof(Wrapper<S>));
        new (storage) Wrapper<S>(std::forward<S>(obj));
    }
};

struct Foobar{};

int main()
{
    Container<Foobar> cont;
    Foobar foobar;
    cont.push_back(foobar);
    return 0;
}

here的一个例子,我不明白我在做什么有什么不同:

template <class T, class Allocator = allocator<T> >
class vector {
public:
    ...
    void push_back(T&& x);       // fully specified parameter type ⇒ no type deduction;
    ...                          // && ≡ rvalue reference
};


编辑: 此问题的解决方案是修改push_back,以从用于实例化Wrapper 的类型中删除引用:

template<class S>
void push_back(S&& obj) {
    typedef std::remove_reference<S>::type U;
    void *storage = malloc(sizeof(Wrapper<U>));
    new (storage) Wrapper<U>(std::forward<S>(obj));
}

【问题讨论】:

  • “通用”引用需要使用deduced模板参数。
  • 标准术语现在是转发参考。 @KerrekSB 也可以是推导出的auto 类型。
  • Wrapper(S&amp;&amp; obj) 中的S 在调用构造函数时不会推导出来,只有在定义对象Wrapper&lt;S&gt; 时才会推导出来。因此,它是一个右值引用,而不是一个转发引用。

标签: c++ parameter-passing


【解决方案1】:

没有涉及Wrapper 的实现的通用引用。您的代码中唯一的通用引用是Container&lt;&gt;::push_back 的参数。

调用cont.push_back(foobar);时,push_back的参数S推导出为Foobar &amp;

稍后您尝试使用S == Foobar &amp; 实例化您的Wrapper&lt;S&gt;。参考折叠规则规定在Wrapper的构造函数参数声明中S &amp;&amp;变成Foobar &amp;const S &amp;也变成Foobar &amp;

这意味着您最终会得到两个所谓的“重载”Wrapper::Wrapper 构造函数,它们具有相同的签名。这就是您观察到错误消息的原因。

如果您尝试使用左值引用类型的模板参数实例化std::vector,您将遇到与push_back 重载完全相同的问题。然而,这种尝试编译通常会由于其他原因而惨遭失败,远在它到达push_back 重载之前。

一个更精炼的例子如下所示

template <typename T> struct MyVector {
  void foo(T &&) {}
  void foo(const T &) {}
};

int main() {
  MyVector<int &> v;
}

会产生同样的错误。

这里相当不明显的部分是const T &amp;T = U &amp; 实际上变成U &amp; 而不是const U &amp;。但事实确实如此。

【讨论】:

  • 好的...现在更有意义了。 assert(std::is_same&lt;S, Foobar&amp;&gt;::value) 通过(在 push_back 的正文中)我以为我正在处理 assert(std::is_same&lt;S, Foobar&gt;::value)
猜你喜欢
  • 1970-01-01
  • 2011-11-16
  • 1970-01-01
  • 1970-01-01
  • 2017-07-19
  • 2011-02-16
  • 2010-11-18
  • 2018-10-06
  • 2017-01-11
相关资源
最近更新 更多