【问题标题】:Derived template class can't find move constructor for base template class派生模板类找不到基模板类的移动构造函数
【发布时间】:2021-08-09 05:01:21
【问题描述】:

我有一个相当大的课程,它被减少到下面的最低失败示例:

#include <vector>

template <typename T> class Base {
public:
  Base(std::vector<T> &&other) : map{other} {}

private:
  const std::vector<T> map;
};

template <typename T> class Derived : public Base<T> {
public:
  Derived(std::vector<T> &&other) : Base<T>{other} {}
};

int main() {
  Derived<double>(std::vector<double>{1,2,3});
}

当我运行它时,我得到了

$ clang++ -std=c++17 -O3 main.cpp && ./a.out
main.cpp:13:37: error: no matching constructor for initialization of 'Base<double>'
  Derived(std::vector<T> &&other) : Base<T>{other} {}
                                    ^      ~~~~~~~
main.cpp:17:3: note: in instantiation of member function 'Derived<double>::Derived' requested here
  Derived<double>(std::vector<double>{1,2,3});
  ^
main.cpp:3:29: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'std::vector<double>' to 'const Base<double>' for 1st argument
template <typename T> class Base {
                            ^
main.cpp:3:29: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'std::vector<double>' to 'Base<double>' for 1st argument
template <typename T> class Base {
                            ^
main.cpp:5:3: note: candidate constructor not viable: no known conversion from 'std::vector<double>' to 'std::vector<double> &&' for 1st argument
  Base(std::vector<T> &&other) : map{other} {}
  ^
1 error generated.

我不明白为什么这会给我一个编译错误。我希望第 13 行的 Base&lt;T&gt;{other} 调用第 5 行的构造函数,因为我传入了 other,它在 Derived 的构造函数参数中声明为右值 (std::vector&lt;T&gt; &amp;&amp; other)。但是,编译器说它是一个左值 (std::vector&lt;double&gt;)。

【问题讨论】:

  • Base(std::vector&lt;T&gt; &amp;&amp;other) : map{std::move(other)} {} 可能会更符合预期。
  • 这也有效。我只是好奇为什么编译器似乎删除了右值。标准中是否有说明这种行为是可以预期的?
  • 如果它有一个名字(比如...other),那么它不是右值,除非你使用std::move 将它“转换”为右值。 void Foo(Bar&amp;&amp;) 正在请求一个右值,Foo(std::move(bar)) 正在授予将其用作右值的权限,但直到m_bar = std::move(bar); 才真正发生在 Foo 例程中。

标签: c++ templates inheritance c++17


【解决方案1】:

因为我传入了在 Derived 的构造函数参数中声明为右值的 other (std::vector && other)

其实在Derived(std::vector&lt;T&gt; &amp;&amp;other)的范围内,other是一个左值,类型是右值引用。这是一个常见的混淆点。看看强大的cppreference

以下表达式是左值表达式:

  • 变量、函数、模板参数对象(C++20 起)或数据成员的名称,无论其类型如何,例如 std::cin 或 std::endl。 即使变量的类型是右值引用,由其名称组成的表达式也是左值表达式;

您需要在Derived 的构造函数中通过std::move()other 显式转换为右值:

template <typename T> class Derived : public Base<T> {
public:
  Derived(std::vector<T> &&other) : Base<T>{std::move(other)} {}
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-20
    • 2014-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-05
    • 1970-01-01
    相关资源
    最近更新 更多