使用引用构造模板类无法编译

问题描述 投票:0回答:1

我正在构建一个必须能够保存值或引用的模板类。 我正在构建 C++11 兼容性库。

这是该类的相关代码

template<typename T>
    class Foo
    {
      private:
        T _Data;

      public:
        Foo(const T& i_Data) :
          _Data(i_Data)
        {}

        virtual ~Foo()
        {}

        Foo(const Foo &i_Other):
          _Data(i_Other._Data)
        {};

        Foo(Foo &&io_Other):
        _Data(std::move(io_Other._Data))
        {}
        // etc..
     };

以这种方式创建 Foo 对象时,代码可以正常工作:

double Bar = 2.5;
Foo<double&> f = Bar; // This does not compile (in c++11, C++20 works though)
                      // error: cannot bind non-const lvalue reference of type ‘double&’ to an rvalue of type ‘std::remove_reference<double&>::type’ {aka ‘double’}
Foo<double&> f(Bar);  // This does compile

我想,当使用第一行时,编译器尝试构建一个临时 Foo,然后将其移动到 Foo 中,尽管我不明白为什么以及如何干净地避免这种情况(当然,我可以删除移动构造函数但这是一个俗气的修复)

另外,为什么它适用于 C++17 而不是 C++11。据我所知,这不是与模板推导相关的问题,因此这在两个标准中应该是相同的,对吗?

c++ c++11 templates
1个回答
3
投票

Foo<double&>
中,采用
const T&
的构造函数将具有您可能没有预料到的类型,这是引用崩溃的结果。

您正在形成一个“对

double
的左值引用的const左值引用”,它会折叠成“对
double
的引用”,因此您的构造函数实际上是:

Foo(double& i_Data)

因此,

Foo<double&> f = Bar;

...完全没问题,因为

Bar
是左值。

在 C++17 之前,在这种情况下没有强制复制省略,上面的行将隐式将

Bar
转换为
Foo<double&>
,然后使用移动构造函数,但您的移动构造函数不处理
T = double&
适当地。 编译器可以忽略此副本和对移动构造函数的调用,但至少在纸面上,该调用必须有效。

自 C++17 起,复制初始化只需直接调用

Foo(const T&)
,不会创建任何临时对象。

© www.soinside.com 2019 - 2024. All rights reserved.