(我还不明白根本原因,所以标题可能不正确。)
\n我有以下无法编译的 C++ 代码:
\n#include <iostream>\n#include <memory>\n#include <vector>\n#include <variant>\n#include <optional>\n\ntemplate <typename T>\nclass A {\n public:\n ~A() = default;\n std::unique_ptr<int> ptr = nullptr;\n};\n\ntemplate <typename T>\nclass B : public A<std::vector<T>> {\n public:\n static B<T> Create() {\n return B<T>();\n }\n};\n\nusing AllTypes = std::variant<B<int64_t>, B<uint64_t>, B<double>>;\n\nstd::optional<AllTypes> Get() {\n // Error! No viable conversion!\n return B<int64_t>::Create();\n}\nRun Code Online (Sandbox Code Playgroud)\n错误信息是:
\nmain.cpp: In function \xe2\x80\x98std::optional<std::variant<B<long int>, B<long unsigned int>, B<double> > > Get()\xe2\x80\x99:\nmain.cpp:34:28: error: could not convert \xe2\x80\x98B::Create() [with T = long int]()\xe2\x80\x99 from \xe2\x80\x98B\xe2\x80\x99 to \xe2\x80\x98std::optional, B, B > >\xe2\x80\x99\n 34 | return B<int64_t>::Create();\n | ~~~~~~~~~~~~~~~~~~^~\n | |\n | B<long int>\nRun Code Online (Sandbox Code Playgroud)\n可以在此处重现该错误: https: //onlinegdb.com/2H-K9x0kq。
\n但如果我删除唯一的 ptr 变量ptr,它可以正确编译。如果我将 ptr 成员移动到子类,B它也会编译。
任何人都可以给出一些关于问题所在的提示吗?现在我不知道要搜索什么关键字/规则。非常感谢!
\n更新:
\n让我首先简化您的示例。我猜想已经有了显着的简化,但是还有更多的层可以被取消。特别是,B这是不必要的,就像将 包装variant在另一个模板中一样。
#include <memory>
#include <variant>
class A {
public:
virtual ~A() = default; // will be used as a base class
std::unique_ptr<int> ptr = nullptr;
};
std::variant<A, int> Get() {
// Error! No viable conversion!
return A();
}
Run Code Online (Sandbox Code Playgroud)
正如您所报告的,如果unique_ptr删除它,这将起作用。这告诉我什么?的特性之一uniqur_ptr就是不可复制;有时此属性会引发构造错误。
另一个难题是声明析构函数会抑制移动构造函数。最终结果是您的类A既不能被复制(因为unique_ptr)也不能被移动(因为用户声明的析构函数)。因此,呈现这种情况的另一种方式如下:
#include <variant>
class A {
public:
A() = default; // <-- must be explicitly declared now
A(const A&) = delete; // <-- Was deleted because of the `unique_ptr`
A(A&&) = delete; // <-- Was deleted because of the user-declared destructor
};
std::variant<A, int> Get() {
// Error! No viable conversion!
// Can neither copy nor move this temporary object into a `variant`.
return A();
}
Run Code Online (Sandbox Code Playgroud)
一种修复方法是删除用户声明的析构函数。然而,由于涉及到继承,这不是一个好的选择。另一个修复是声明移动构造函数(以及移动赋值,如果需要的话)。
#include <memory>
#include <variant>
class A {
public:
virtual ~A() = default; // will be used as a base class
A() = default;
A(A&&) = default; // <-- Allow move construction
std::unique_ptr<int> ptr = nullptr;
};
std::variant<A, int> Get() {
// No error!
return A();
}
Run Code Online (Sandbox Code Playgroud)