8

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

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可以隐式转换为 a Foo,但没有其他值”

4

4 回答 4

5

如果你不介意Foo b = nullptr;工作,很容易破解。有一个显式构造函数 fromint和一个隐式 from 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 会杀死它。但是,在这种情况下,它应该比指针构造函数更好。

于 2013-06-20T15:36:51.517 回答
0
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
于 2013-06-20T15:02:22.270 回答
-1

我承认我还没有完全掌握 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&&”</p>

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

于 2013-06-20T15:46:48.273 回答
-1

我的一个想法是:

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

这行为明智吗?

于 2013-06-20T15:16:16.843 回答