提问人:Michael 提问时间:7/2/2023 最后编辑:Michael 更新时间:7/2/2023 访问量:136
使用默认参数在 optional 中unique_ptr 内部的类的正向声明失败
Forward declaration of class inside unique_ptr inside optional with default argument fails
问:
我有以下一段代码
// DoSomething.h
class Foo;
void doSomething(std::optional<std::unique_ptr<const Foo>> f = std::nullopt);
如果我在没有文件定义的情况下包含任何地方,则不会编译,即使它甚至没有调用该函数。相反,删除默认参数,一切都可以正常编译。DoSomething.h
Foo
doSomething
=std::nullopt
我的假设是该问题与unique_ptr的删除器接口有关,我的问题是如何解决这个问题,以便我可以在这种情况下转发声明?Foo
谢谢
编辑:我不想更改此函数的签名,我知道我可以通过重载或删除可选用途来解决这个问题。我想知道为什么这不起作用。
以下注意 - 在切换 with 时,相同的代码编译得非常好。这意味着应该可以使其与 .我知道他们的删除器的界面略有不同,而且我对它不够熟悉。std::unique_ptr
std::shared_ptr
std::unique_ptr
答:
Cppreference 对 的模板参数说了以下几点:std::optional
T - 要管理其初始化状态的值的类型。该类型必须满足可破坏的要求
std::unique_ptr<T>
不完整时不可破坏。T
函数的默认参数在声明该函数时实例化。
因此,在实例化对象时不满足 的要求。std::optional
如注释中所述,您可以通过重载函数而不是使用默认参数来解决问题。此外,指针会公开一个 null 值,因此在大多数情况下不是必需的。std::optional<pointer-type>
阅读您的编辑后跟进:
class Foo;
using FooDeleter = std::function<void(Foo const*)>;
void doSomething(std::optional<std::unique_ptr<const Foo, FooDeleter>> f = std::nullopt);
此代码将正常编译。它与类似于 的已擦除删除程序类型一起使用。如果使用默认删除器()进行实例化,则问题是:
的简化定义如下所示:std::unique_ptr
std::shared_ptr
unique_ptr
std::default_delete
std::default_delete
template <typename T>
class default_delete {
void operator()(T* p) const {
p->~T();
}
};
所以在实例化过程中,上面的代码将被实例化。因为它对未声明的析构函数进行调用,编译将失败。
如果实例化,则只会调用 的 ,这与析构函数的定义无关。std::optional<std::unique_ptr<Foo>>
Foo
std::optional<std::unique_ptr<Foo, FooDeleter>>
operator()
std::function<...>
Foo
评论
T
shared_ptr<T>
T
shared_ptr
unique_ptr
Deleter
shared_ptr
T
= std::nullopt
unique_ptr
T
T
= std::nullopt
std::optional<std::unique_ptr<Foo>>
评论
nullptr
=std::nullopt
默认参数,一切都编译良好”,所以你有一个解决方案,重载函数而不是默认参数。language-lawyer
void doSomething();
std::nullopt
Foo
Foo
doSomething