Я определил обычай enum
для удобства над определенным классом, и теперь он мешает его обработке более общими процессами.
Как я должен выполнить этот Typecast?
// A templated value holder:
template <typename T>
struct Holder {
T _value;
};
// A more general process..
template <typename T>
struct General {
Holder<T> *holder;
};
// ..over integral types:
struct IntGeneral : General<int> {};
// Here is something interesting: I can tell that this process will work on
// any enum type. But I've found no way to make this explicit.
// Convenience for a particular case
typedef enum {One, Two, Three} Enum;
typedef Holder<Enum> Particular;int main() {
Particular* a( new Particular { One } );
IntGeneral ig { static_cast<Holder<int>*>(a) }; // compiler grumbles
return EXIT_SUCCESS;
}
Вот что я получаю:
error: invalid static_cast from type ‘Particular* {aka Holder<Enum>*}’ to type ‘Holder<int>*’
Есть ли способ сохранить удобный Enum
и получить этот код скомпилирован?
РЕДАКТИРОВАТЬ: Это оказалось XY проблема. Ответ на Y был принят здесь, и некоторые обсуждали.
X был перемещен в Другой вопрос. Прошу прощения за неудобства.
Достаточно ли заменить:
IntGeneral ig { static_cast<Holder<int>*>(a) }; // compiler grumbles
С:
IntGeneral ig { new Holder<int>{a->_value} };
Поскольку это структура, вы можете получить доступ к значению. Лично я бы использовал геттеры и сеттеры, но, как представлено, это должно делать то, что вы хотите.
вперемежку
Вы можете заменить:
typedef Holder<Enum> Particular;
С:
typedef Holder<int> Particular;
Так как int
может держать Enum
Вы можете добавить шаблонную функцию преобразования, которая позволит Holder<T>
быть преобразованным в Holder<U>
если T
конвертируется в U
а также T
это перечисление:
template <typename T>
struct Holder {
T _value;
template <typename U,
typename = std::enable_if_t<
std::is_convertible<T, U>::value &&
std::is_enum<T>::value
>>
operator Holder<U>() const {
return {_value};
}
};
Потенциально просто достаточно проверки конвертируемости, в зависимости от вашего варианта использования.
Это позволит вам написать:
Holder<int> i = Holder<Enum>{One};
Но это не позволит вам выполнить преобразование указателя в качестве приведения. Вы должны были бы выделить совершенно новый Holder<int>*
хранить Holder<Enum>*
,
Я думаю, что самый простой способ заставить это работать — специализироваться Holder<Enum>
так что он имеет неявное преобразование в Holder<Int>
,
template<>
struct Holder<Enum> {
Enum _value;
operator Holder<Int>() const { return { _value }; }
};
Это будет делать копии перечисления, так что это может сделать не совсем то, что вы хотите, в зависимости от того, что идет в General
процессы.
Проблема в том, что static_cast
не предназначен для наведения указателей разных типов. Я предлагаю вам использовать reinterpret_cast
, это должно сделать работу. Кроме того, вы не можете создать экземпляр объекта типа IntGeneral
с указателем.
Есть несколько изменений, которые вы можете сделать:
И для списка инициализации IntGeneral (это странное имя, потому что оно не является общим, но я понимаю) Начните с адреса «Holder *».
struct HolderBase {};
template <typename T>
struct Holder : HolderBase{
Holder(T value){ _value = value; }
T _value;
};
template <typename T>
struct General {
General(Holder<T>* h){ holder = h; }
Holder<T>* holder;
};
struct IntGeneral : General<int> {
IntGeneral(Holder<int>* holder) : General<int>(holder){}
};
typedef enum { One, Two, Three } Enum;
typedef Holder<Enum> Particular;int main() {
HolderBase* a(new Particular{ One });
IntGeneral ig{ static_cast<Holder<int>*>(a) };
return 0;
}
надеюсь, это то, что вы искали