禁用std :: optional的转发构造函数

时间:2019-05-24 19:42:03

标签: c++ perfect-forwarding qdatastream stdoptional

我已经使用模板转换运算符扩展了QDataStream,以便数据流从自身加载并转换为任何受支持的类型,例如:

class ConvertibleQDataStream : public QDataStream
{
public:

    using QDataStream::QDataStream;

    template <class T>
    explicit operator T ()
    {
        T t;
        *this >> t;
        return t;
    }
};

并且可以通过重载运算符>>来添加对QDataStream不支持的类型的支持,例如:

template <class T>
ConvertibleQDataStream&
operator >> (ConvertibleQDataStream& ds, std::vector<T>& v)
{
    //Called for std::vector's.
    return ds;
}

想法是能够直接从流中构造非默认的可构造类,如下所示:

class Bar
{
public:

    Bar(ConvertibleQDataStream&);
};

class Foo
{
    int mInt;
    std::vector<double> mVector;
    Bar mBar;

public:

    Foo(ConvertibleQDataStream& ds) :
        mInt(ds),     //Calls operator >> for int and converts to int 
        mVector(ds),  //Calls operator >> for std::vector<T> and converts to std::vector<T>
        mBar(ds)      //Plain constructor call 
    {}
};

这很好用,除非成员是std::optional。代替std::optional的模板转换运算符,调用ConvertibleQDataStream的转发构造函数:

template <class T>
ConvertibleQDataStream&
operator >> (ConvertibleQDataStream& ds, std::optional<T>& o)
{
    //Never called :(
    return ds;
}

class Qux
{
    std::optional<Bar> mOptional;

public:

    Foo(ConvertibleQDataStream& ds) :
        mOptional(ds) //calls Bar::Bar(ConvertibleQDataStream&) rather then operator >> for std::optional<T> due to forwarding c'tor.
    {}
};

可以禁用std::optional的转发构造函数吗?或其他解决方法。

1 个答案:

答案 0 :(得分:2)

这不是选项的问题,这是设计中的问题,其中可以从ConvertibleQDataStream构造mOptional。

C ++转换规则可能是一场噩梦,在这种情况下,应该通过提供明确的get运算符来避免。

class ConvertibleQDataStream : public QDataStream
{
public:
    using QDataStream::QDataStream;

    template <class T>
     T Get() const
    {
        T t;
        *this >> t;
        return t;
    }
};

class Qux
{
    std::optional<Bar> mOptional;

public:

    Foo(ConvertibleQDataStream& ds) :
        mOptional(ds.Get<std::optional<Bar>>())
    {}
};