模板化类构造函数在结构中使用错误的重载

Templated class constructor uses wrong overload when in struct

本文关键字:错误 重载 结构 构造函数      更新时间:2023-10-16

测试如下:

class NotInit{};
NotInit NOT_INIT;
template<class T>
class Optional{
  T value;
  bool has_value;
public:
  Optional() : value(), has_value(false){}
  explicit Optional(NotInit):value(), has_value(false) {}
  explicit Optional(T const & val):value(val), has_value(true){}
  explicit Optional(Optional<T> const & other) {}
  Optional& operator=(Optional<T> const & other){}
  Optional& operator=(T const & other){}
};
enum X {
  FIRST
};
struct Some {
  Optional<X> member;
};
int main(int, char**){
  Optional<X> const opt(NOT_INIT);
  Some s = {NOT_INIT};
  return 0;
}

Clang 3.4 抱怨:

../st.cpp:31:12: error: no viable conversion from 'NotInit' to 'Optional<X>'
        Some s = {NOT_INIT};
                  ^~~~~~~~
1 error generated.

为什么它抱怨结构初始化,而抱怨可变量?为什么它没有选择具有正确参数的构造函数?

缺少什么重载,以便我可以使用它来初始化结构?

无法使用 boost,我不确定如果使用 boost::optional 不会出现此错误。

您正在将构造函数标记为explicit 。因此,当您尝试使用大括号初始值设定项列表初始化struct Some时,您将触发隐式转换...

此处可防止这种情况:

class NotInit;
template <typename T>
class Optional {
    // Here => Optional(NotInit) cannot be called implicitly
    explicit Optional(NotInit):value(), has_value(false) {}
};
/* ... */
Some s = {NOT_INIT}; // Implicit call to Optional<X>(NotInit): whoops!

如果删除explicit,则可以保留:

Some s = {NOT_INIT};

如果您选择不这样做,则必须像这样实例化s

Some s = {Optional<X>(NOT_INIT)};

在任何情况下,您都必须删除复制构造函数上的 explicit 关键字(它必须执行复制而不是"虚拟"构造函数)。
为什么?因为一旦Optional<X>对象从NOT_INIT构建,就必须复制s.member

注意:您还可以提供一个移动构造函数,在这种情况下会更合适,因为您从NOT_INIT转换中获得的对象是右值。