Могу ли я перегрузить неявную инициализацию до 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, но никакой другой ценности

8

Решение

Если ты не возражаешь 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потому что иначе СФИНАЭ убивает его. В этом случае, однако, он должен быть лучше, чем конструктор указателя.

5

Другие решения

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
0

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

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

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

-1

Я признаю, что еще не полностью освоил семантику 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: ошибка: невозможно привязать значение типа int к значению int&&»

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

-1
По вопросам рекламы [email protected]