2017-02-13 10 views
0

У меня есть класс флагов, который является только оболочкой вокруг целого числа, и я хочу реализовать явное преобразование в произвольные целые типы на основе правил преобразования для базового целочисленного типа.C++ явное интегральное пользовательское преобразование

т.е.

говорят, у меня есть класс по линиям (без учета нерелевантных членов)

class Flags { 
    unsigned int v; 
    explicit operator unsigned int() { return v; } 
} 

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

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, если это имеет любое применение.

+0

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

+0

«Явные» операторы преобразования * должны быть вызваны явно или путем преднамеренного литья. Выполнение 'static_cast (flags);' будет запрашивать оператор преобразования 'unsigned long long()', который не является тем, что у вас есть, поэтому программа плохо сформирована. – WhiZTiM

+0

Из текущих ответов первая точка первая, как я и ожидал, но никто не упомянул о погоде, это простой способ сказать, используя шаблон, чтобы определить все интегральные преобразования, которые являются допустимыми, укажите размер моего класса flags. Я также понимаю, что это будет работать для неявных преобразований, однако я не хочу, чтобы мой класс был неявно конвертируемым в интегральные типы, поскольку это позволяет избежать случайных преобразований. Однако я также не хочу думать о том, что такое базовый тип, когда я делаю явное преобразование, пока мой целевой тип может содержать все бит флага. – glenflet

ответ

1

я мог еще преобразовать к интегральному типу, кроме междунар сказать по

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); 
+0

Что означает «стандартная последовательность конверсий», что-нибудь? –

+0

@ T.C., Компилятор может преобразовать 'Flags' в' unsigned int', а затем 'unsigned int' в' unsigned long long', если 'Flags' ->' int' были стандартным преобразованием. Это была моя мысль. –

+0

Итак? Он также может это сделать, если 'operator unsigned int' не был« явным », но это все еще не стандартное преобразование. В любом случае это не имеет большого отношения к способности создавать неявные последовательности преобразования; конечно, * явная * функция преобразования не может использоваться для формирования * неявной * последовательности преобразования, стандартной или нет, точного соответствия типа или нет. –

1

Это static_cast попытка подпадает под [expr.static.cast]/4, что примерно говорит, что вы можете сделать static_cast<T>(e), если вы можете сделать T t(e); для некоторых изобретенных переменной t (есть некоторые забавные танцы в формулировках, чтобы заботиться о гарантированной элизии и 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.