C++ 为什么可以';t我有标准::可选<;T>;T在哪里是抽象的?
这不起作用:C++ 为什么可以';t我有标准::可选<;T>;T在哪里是抽象的?,c++,templates,virtual,abstract,optional,C++,Templates,Virtual,Abstract,Optional,这不起作用: struct Type { virtual bool func(const std::string& val) const noexcept = 0; } // in main optional<Type> = some_function_returning_optional_type(); 结构类型{ 虚拟布尔函数(conststd::string&val)constnoexcept=0; } //大体上 可选=某些函数返回可选类型(); 并失败
struct Type {
virtual bool func(const std::string& val) const noexcept = 0;
}
// in main
optional<Type> = some_function_returning_optional_type();
结构类型{
虚拟布尔函数(conststd::string&val)constnoexcept=0;
}
//大体上
可选=某些函数返回可选类型();
并失败,并显示错误消息:
error: cannot declare field 'std::experimental::fundamentals_v1::_Optional_base<Type, false>::<anonymous union>::_M_payload' to be of abstract type 'Type'
错误:无法将字段“std::experimental::fundamentals_v1::_Optional_base::::_M_payload”声明为抽象类型“type”
将类型
更改为具有非纯函数可以工作,但在这种情况下不合适,因为在我的代码中不能有类型
的实例,只有继承自它的类才能存在。std::optional
将其值存储在适当的位置-因此,它需要知道T
的大小才能正确工作,T
必须是可以实例化的具体类型。您可以将std::optional
视为:
template <typename T>
struct optional
{
std::aligned_storage_t<sizeof(T), alignof(T)> _data;
bool _set;
};
模板
结构可选
{
std::对齐的存储数据;
布尔集;
};
抽象类型表示接口多态性,使用抽象类型需要某种间接寻址<代码>标准::可选的没有任何设计上的间接性。你的可选方案当然会起作用,但如果我不得不写的话,我会很生气
x.value()->do_something();
我担心用户可能会做一些愚蠢的事情:
x.value().reset(); // now what?
我们可以通过使用包装器实现非多态接口的多态性
这里有一个方法:
#include <optional>
#include <iostream>
// the Foo interface/base class
struct Foo
{
virtual ~Foo() = default;
virtual Foo* clone() const { return new Foo(*this); }
virtual void do_something() {
std::cout << "something Fooey\n";
}
};
// a service for managing Foo and classes derived from Foo
struct FooService
{
template<class Arg>
Foo* clone(Arg&& arg)
{
using d_type = std::decay_t<Arg>;
return new d_type(std::forward<Arg>(arg));
}
template<class Arg>
Foo* clone(Foo* arg)
{
return arg->clone();
}
Foo* release(Foo*& other) noexcept
{
auto tmp = other;
other = nullptr;
return tmp;
}
};
// implement the Foo interface in terms of a pimpl
template<class Holder>
struct BasicFoo
{
decltype(auto) do_something() {
return get().do_something();
}
private:
Foo& get() noexcept { return static_cast<Holder*>(this)->get_impl(); }
Foo const& get() const noexcept { return static_cast<Holder const*>(this)->get_impl(); }
};
// a type for holding anything derived from a Foo
// can be initialised by anything Foo-like and handles copy/move correctly
struct FooHolder : BasicFoo<FooHolder>
{
template
<
class Arg,
std::enable_if_t
<
std::is_base_of_v<Foo, std::decay_t<Arg>>
>* = nullptr
>
FooHolder(Arg&& arg)
: service_()
, ptr_(service_.clone(std::forward<Arg>(arg)))
{}
FooHolder(FooHolder const& other)
: service_()
, ptr_(other.ptr_->clone())
{
}
FooHolder(FooHolder && other) noexcept
: service_()
, ptr_(service_.release(other.ptr_))
{
}
FooHolder& operator=(FooHolder const& other)
{
auto tmp = other;
std::swap(ptr_, tmp.ptr_);
return *this;
}
FooHolder& operator=(FooHolder && other) noexcept
{
auto tmp = std::move(other);
std::swap(ptr_, tmp.ptr_);
return *this;
}
~FooHolder()
{
delete ptr_;
}
Foo& get_impl() noexcept { return *ptr_; }
Foo const& get_impl() const noexcept { return *ptr_; }
FooService service_;
Foo* ptr_;
};
// now we can supply as many overrides of Foo as we like
struct Bar : Foo
{
virtual Foo* clone() const { return FooService().clone(*this); }
virtual void do_something() {
std::cout << "something Barey\n";
}
};
int main()
{
std::optional<FooHolder> opt;
// note that we're initialising cleanly
opt = Bar {};
// and we don't expose the pointer so the user can't
// destroy the pimpl accidentally
opt.value().do_something();
}
#包括
#包括
//Foo接口/基类
结构Foo
{
virtual~Foo()=默认值;
虚拟Foo*clone()常量{返回新Foo(*this);}
虚拟空间做某事{
std::cout clone();
}
Foo*发布(Foo*和其他)无例外
{
自动tmp=其他;
其他=空PTR;
返回tmp;
}
};
//根据pimpl实现Foo接口
模板
结构BasicFoo
{
decltype(auto)do_something(){
return get().do_something();
}
私人:
Foo&get()noexcept{return static_cast(this)->get_impl();}
Foo const&get()const noexcept{return static_cast(this)->get_impl();}
};
//用于保存从Foo派生的任何内容的类型
//可以通过任何类似Foo的方式初始化,并正确处理复制/移动
结构FooHolder:BasicFoo
{
模板
<
类Arg,
std::如果启用,则启用
<
std::是v的基础吗
>*=nullptr
>
食物持有者(Arg&&Arg)
:服务
,ptr_(服务克隆(std::forward(arg)))
{}
食品持有者(食品持有者常量和其他)
:服务
,ptr_(其他.ptr_->clone())
{
}
食品持有者(食品持有者和其他)无例外
:服务
,ptr_(服务发布(其他ptr_))
{
}
FooHolder和运算符=(FooHolder常量和其他)
{
自动tmp=其他;
标准::交换(ptr_u,tmp.ptr_u);
归还*这个;
}
FooHolder和operator=(FooHolder和其他)无例外
{
自动tmp=标准::移动(其他);
标准::交换(ptr_u,tmp.ptr_u);
归还*这个;
}
~FooHolder()
{
删除ptr;
}
Foo&get_impl()noexcept{return*ptr_;}
Foo const&get_impl()const noexcept{return*ptr_;}
食物服务;;
Foo*ptr;
};
//现在,我们可以提供任意数量的Foo覆盖
结构栏:Foo
{
虚拟Foo*clone()常量{return FooService().clone(*this);}
虚拟空间做某事{
std::cout So,当我正确理解这一点时,将类型
隐藏在a(智能)后面指针就可以了?@musicmatze:你可以有一个std::optional
。但是为什么不使用std::unique_ptr
?@musicmatze多态性总是需要间接的。很好的建议,谢谢。在它周围有一个optional
在语义上更合适,而且它不是运行时关键的,所以我很乐意为它付费is price!谢谢!@musicmatze指针隐式为空,表示无效的返回值。您如何实例化要放入可选中的抽象类型?如果您实际实例化的是具体类型,但使用指向抽象类型的指针,则可以放入指针(或智能指针)但是,请注意,只有当nullptr
不够时,您才需要一个可选项,并且您需要在无法创建nullptr
时处理特殊情况。