【问题标题】:Can I overload an implicit initialization to 0?我可以将隐式初始化重载为 0 吗?
【发布时间】:2013-06-17 12:17:50
【问题描述】:

是否可以编写一个使这些有效的类:

Foo a;
Foo b = 0;
Foo c = b;
Foo d(0);
Foo e(1);
Foo f = Foo(1);

但这些不是:

int x;
Foo a = x;
Foo b = 1;
Foo c = 2;
//etc

基本上,我的规则是“常量0 可以隐式转换为Foo,但没有其他值”

【问题讨论】:

  • Foo e(1); 呢?这怎么有效?
  • @LuchianGrigore:它们在语义上是否相同?如果是这样,我想我可以宣布无效。
  • 也许您可以尝试使用带有std::nullptr_t 的构造函数(只是一个想法......)
  • 如果xconst int x = 0;,你希望a 的初始化成功吗?

标签: c++ constructor initializer explicit-constructor


【解决方案1】:
Foo e(1); 

将调用 Foo 的非显式构造函数,以 int 作为参数。 本质上,这一行将通过尝试使用此 int 构造函数将 int 转换为 Foo 来做同样的事情。

Foo b = 1;

您不能阻止直接处理该 int 的某些值。 如果你有你的构造函数explicit,你也不能写下一行。

Foo b = 0;

gx_ 正确地指出 0 可以转换为 std::nullptr_t。 以下内容将根据您的意图起作用。

Foo(std::nullptr_t x) : member(0) { }
explicit Foo(int c) : member(c) { }
// ...
Foo a = 0; // compiles
Foo b = 1; // doesn't compile

// Note:
int do_stuff (void) { return 0; }
Foo c = do_stuff(); // doesn't compile

【讨论】:

  • 不,直接与复制初始化。
  • 一个explicit Foo(int); 加上一个Foo(nullptr_t); 怎么样?
【解决方案2】:

我的一个想法是:

Foo(const uint32_t c) : member(0) { static_assert(c == 0, "Nope"); }
explicit Foo(uint32_t c) : member(c) { }

这样做是否合理?

【讨论】:

  • 那甚至无法编译。就重载解析而言,const uint32_t 参数和uint32_t 参数是一回事。
【解决方案3】:

如果您不介意 Foo b = nullptr; 工作,那么很容易破解。有一个来自int 的显式构造函数和一个来自std::nullptr_t 的隐式构造函数。

如果您确实介意这种工作,我不确定它是否可能。区分文字0 和其他整数文字的唯一方法是前者隐式转换为指针和nullptr_t。所以nullptr 会更喜欢nullptr_t 参数而不是指针参数,因此通过拥有两个构造函数,您可以过滤掉nullptr 参数。但是,0 到指针的转换和 nullptr_t 的转换等级相同,因此这会导致 0 参数不明确。

嗯......这样的事情可能会起作用:

class Foo {
  struct dummy;
public:
  explicit Foo(int); // the version that allows Foo x(1);
  Foo(dummy*); // the version that allows Foo x = 0;
  template <typename T,
            typename = typename std::enable_if<
                std::is_same<T, std::nullptr_t>::value>::type>
  Foo(T) = delete; // the version that prevents Foo x = nullptr;
};

我还没有真正尝试过这个。理论上,模板应该只在参数为nullptr 时参与重载决议,否则 SFINAE 会杀死它。但是,在这种情况下,它应该比指针构造函数更好。

【讨论】:

    【解决方案4】:

    我承认我还没有完全掌握 C++11 的右值语义,但这似乎是你想要的:

    class Foo
    {
        public:
        Foo(int&&) {}
    };
    
    int main()
    {
        Foo a(123);
        int x = 123;
        Foo b(x); // error here, line 11
        return 0;
    }
    

    结果:

    prog.cpp:11: 错误:无法将‘int’左值绑定到‘int&&’

    欢迎评论,如果此代码有任何我没有注意到的警告,或者您可以向我保证它没有。

    【讨论】:

    • 有趣,但我的目标是x == 0的具体案例;
    • @eric 啊,没有意识到这一点。你说Foo e(1); 应该是有效的:/
    猜你喜欢
    • 2021-11-15
    • 2017-10-24
    • 2020-09-17
    • 1970-01-01
    • 2012-06-24
    • 2010-11-02
    • 2022-11-15
    • 2011-02-15
    • 2019-05-12
    相关资源
    最近更新 更多