【问题标题】:Disable std::optional's forwarding constructor禁用 std::optional 的转发构造函数
【发布时间】:2019-10-11 09:56:33
【问题描述】:

我使用模板转换运算符扩展了 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 的转发构造函数吗?或者其他解决方法。

【问题讨论】:

  • Foo(ConvertibleQDataStream&amp; ds){ ds &gt;&gt; mOptional; } 有什么问题?
  • @alterigel:一个类可能有非默认的可构造成员。这些必须在成员初始化器列表中初始化。由于从流中提取数据的顺序很重要,因此无法将某些内容移至构造函数主体。
  • @Unimportant 你的意思是你想让ConvertibleQDataStream::operator T()T=std::optional&lt;Bar&gt; 调用吗?
  • @alterigel 是的,它适用于所有其他类型,但转发构造函数会妨碍。
  • 标准转换优先于用户定义。

标签: c++ perfect-forwarding qdatastream stdoptional


【解决方案1】:

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

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>>())
    {}
};

【讨论】:

  • 它们并不是什么噩梦,允许首选用户定义的转换会导致#define true false 有点混乱。
  • 完美的转发构造函数会导致各种疯狂,即使在 stl. std::optional 表现得特别糟糕: std::optional x; // 空 std::optional y(x); // 你认为这里会发生什么?
  • 不确定您的意思。它们都是空的……因为 x 是空的?它不使用复制构造函数吗?其他构造函数是显式的或条件显式的。
  • @Swift-FridayPie y 实际上包含 false。 std::optionl 可以隐式转换为 bool。
猜你喜欢
  • 2019-09-02
  • 2018-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-15
  • 2017-05-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多