Могу ли я перегрузить неявную инициализацию до 0?

Можно ли написать такой класс, чтобы они действовали:

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, но никакое другое значение не может»


person Eric    schedule 20.06.2013    source источник
comment
А что насчет Foo e(1);? Как это действительно?   -  person Luchian Grigore    schedule 20.06.2013
comment
@LuchianGrigore: Они семантически идентичны? Если так, то я могу объявить это недействительным.   -  person Eric    schedule 20.06.2013
comment
Может быть, вы можете попробовать с конструктором, использующим std::nullptr_t (просто идея ...)   -  person gx_    schedule 20.06.2013
comment
Что, если x был const int x = 0;, хотите ли вы, чтобы инициализация a прошла успешно?   -  person jxh    schedule 20.06.2013
comment
Возможно, это может быть полезно: stackoverflow.com/questions/3299834 / stackoverflow.com/questions/7658060/   -  person Suma    schedule 20.06.2013


Ответы (4)


Если вы не против 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 убьет его. Однако в этом случае он должен быть лучше конструктора указателя.

person Sebastian Redl    schedule 20.06.2013

Foo e(1); 

Вызов неявного конструктора Foo с аргументом int. По сути, эта строка будет делать то же самое, пытаясь преобразовать int в Foo с помощью этого конструктора int.

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
person Pixelchemist    schedule 20.06.2013
comment
Нет, прямая инициализация или инициализация копированием. - person Luchian Grigore; 20.06.2013
comment
Как насчет explicit Foo(int); плюс Foo(nullptr_t);? - person gx_; 20.06.2013

У меня была одна идея:

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

Это ведет себя разумно?

person Eric    schedule 20.06.2013
comment
Это даже не компилируется. Что касается разрешения перегрузки, параметр const uint32_t и параметр uint32_t - это одно и то же. - person Sebastian Redl; 20.06.2013

Признаюсь, я еще не овладел семантикой rvalue в 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: error: невозможно привязать lvalue int к int &&

Комментарии приветствуются, если в этом коде есть какие-либо оговорки, которые я не заметил, или если вы можете меня заверить, что это не так.

person Oktalist    schedule 20.06.2013
comment
Интересно, но я стремлюсь к конкретному случаю x == 0; - person Eric; 20.06.2013
comment
@eric А, я этого не понимал. Вы сказали, что Foo e(1); должен быть действительным: / - person Oktalist; 20.06.2013