У меня есть флаг flags witch — это просто обертка вокруг целого числа, и я хочу реализовать явное преобразование в произвольные целочисленные типы на основе правил преобразования для базового целочисленного типа.
то есть
скажем, у меня есть класс по линии (игнорируя нерелевантных членов)
class Flags {
unsigned int v;
explicit operator unsigned int() { return v; }
}
Могу ли я преобразовать в целочисленный тип, отличный от int, скажем
unsigned long long iflags = static_cast<unsigned long long>(flags);
скорее, чем
unsigned long long iflags = static_cast<unsigned int>(flags);
или мне нужно было бы явно определить оператор преобразования для каждого целочисленного типа, чтобы иметь возможность сделать это?
Обратите внимание, я использую C ++ 14
я прочел http://en.cppreference.com/w/cpp/language/cast_operator но не вижу ничего специфического для целочисленных типов, что заставляет меня думать, что мне нужно явно определить все допустимые преобразования, которых я хочу избежать. Я также был бы доволен функцией преобразования шаблонов, которая потерпит неудачу, если преобразование в целевой тип невозможно, отметив, что я знаю максимальное значение внутреннего целого числа, т.е. все биты флага включены, как макрос / константа FLAGS_MAX
, если это будет полезно.
Тот static_cast
попытка подпадает под [Expr.static.cast] / 4, который примерно говорит, что вы можете сделать static_cast<T>(e)
если вы можете сделать T t(e);
для некоторой придуманной переменной t
(в формулировке есть какой-то забавный танец, чтобы позаботиться о гарантированной исключительности в стиле C и стиля C, который мы можем игнорировать для наших целей).
Эта инициализация контролируется [Dcl.init] /17.7, который говорит, что вы делаете разрешение перегрузки на функции преобразования Flags
с указателем на [Over.match.conv], который имеет это сказать о кандидатах:
Те неявные функции преобразования, которые не скрыты внутри
[Flags
] и тип выхода [unsigned long long
] или тип, который может быть
преобразован в тип [unsigned long long
] через стандартное преобразование
последовательность — функции-кандидаты. Для прямой инициализации те
явные функции преобразования, которые не скрыты в [Flags
] а также
тип доходности [unsigned long long
] или тип, который можно преобразовать в
тип [unsigned long long
] с квалификацией преобразования также
функции-кандидаты.
Ваш explicit operator unsigned int()
ни один не дает unsigned long long
ни тип, который может быть преобразован в него посредством преобразования квалификации (что здесь не имеет значения — это преобразование применимо только к указателю-у); следовательно, это не кандидат. Поскольку набор кандидатов пуст, разрешение перегрузки завершается неудачно, поэтому инициализация некорректна, как и static_cast
,
Могу ли я преобразовать в целочисленный тип, отличный от int, скажем
unsigned long long iflags = static_cast<unsigned long long>(flags);
Нет, ты не можешь.
Вышеуказанное эквивалентно:
unsigned long long temp(flags);
unsigned long long iflags = temp;
Первая строка неверна, так как flags
не может быть неявно преобразовано в unsigned long long
,
Учитывая определение Flags
единственный допустимый метод C ++ для инициализации iflags
это использовать:
unsigned long long iflags = static_cast<unsigned int>(flags);
Если вы удалите explicit
классификатор от оператора конвертации
class Flags {
unsigned int v;
public:
operator unsigned int() { return v; }
}
тогда вы можете использовать
unsigned long long iflags = static_cast<unsigned long long>(flags);