Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么可以';t我有标准::可选<;T>;T在哪里是抽象的?_C++_Templates_Virtual_Abstract_Optional - Fatal编程技术网

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
时处理特殊情况。