Любой способ использовать только оператор класса?

Вроде случайный вопрос ...

Я ищу способ выразить операцию приведения, которая использует определенный оператор экземпляра класса, из которого я выполняю приведение, и генерирует ошибку времени компиляции, если для типа не существует определенного оператора приведения. Так, например, я ищу что-то вроде:

template< typename RESULT_TYPE, typename INPUT_TYPE >
RESULT_TYPE operator_cast( const INPUT_TYPE& tValue )
{
    return tValue.operator RESULT_TYPE();
}

// Should work...
CString sString;
LPCTSTR pcszString = operator_cast< LPCTSTR >( sString );

// Should fail...
int iValue = 42;
DWORD dwValue = operator_cast< DWORD >( iValue );

Интересное примечание: приведенный выше код приводит к сбою компилятора VS2005 C++ и некорректно компилируется в компиляторе VS2008 C++ из-за того, что, как я предполагаю, является ошибкой компилятора, но, надеюсь, демонстрирует идею.

Кто-нибудь знает способ добиться такого эффекта?

Обновлено: дополнительное обоснование, чтобы объяснить, почему вы можете это использовать. Допустим, у вас есть класс-оболочка, который должен инкапсулировать или абстрагироваться от типа, и вы приводите его к инкапсулированному типу. Вы можете использовать static_cast <>, но это может сработать, когда вы хотите, чтобы он потерпел неудачу (то есть: компилятор выбирает оператор, которому разрешено преобразовывать в тип, который вы просили, когда вам нужен сбой, потому что этот оператор отсутствует).

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

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
681
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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

Да, но как насчет приведения к встроенным внутренним типам, когда я не могу добавить явный конструктор или изменить поведение преобразования?

Nick 17.10.2008 00:21

Вы имеете в виду, что хотите изменить поведение приведения по умолчанию между двумя внутренними типами?

Greg Rogers 17.10.2008 00:38

Нет, я конвертирую класс-оболочку во внутренний тип, поэтому я не могу сказать компилятору, что я хочу, чтобы внутренний тип создавался только явно (и это было бы плохо в общем смысле).

Nick 17.10.2008 01:54

звучит так, будто вам нужна специализация шаблона, что-то вроде этого:

/* general template */
template<typename T1, typename T2> T1 operator_cast(const T2 &x);

/* do this for each valid cast */
template<> LPCTSTR operator_cast(const CString &x) { return (LPCTSTR)x; }

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

Поскольку сообщения об ошибках компилятора, связанные с шаблоном, обычно сложно распутать, если вы не против указать каждое преобразование, вы можете заставить компилятор выдавать более информативное сообщение в случае сбоя, указав также определение шаблона по умолчанию. При этом используется тот факт, что компилятор будет пытаться скомпилировать только тот код в шаблонах, который действительно вызывается.

#include <string>

// Class to trigger compiler warning   
class NO_OPERATOR_CONVERSION_AVAILABLE
{
private:
   NO_OPERATOR_CONVERSION_AVAILABLE(){};
};

// Default template definition to cause compiler error
template<typename T1, typename T2> T1 operator_cast(const T2&)
{
   NO_OPERATOR_CONVERSION_AVAILABLE a;
   return T1();
}

// Template specialisation
template<> std::string operator_cast(const std::string &x)
{
   return x;
}

Это сработает, но единственным недостатком будет необходимость явного определения каждого «действительного» варианта вместо написания одной общей версии. Я бы назвал эту версию allowed_cast, чтобы лучше уловить эффект.

Nick 17.10.2008 01:31

Да, я считаю, что смысловая разница допустима. Должен быть способ определить во время компиляции, применяется ли явный оператор преобразования - я могу придумать, как вы можете определить, действительно ли преобразование Любые, но явное сложнее. Я подумаю еще ...

user23167 17.10.2008 01:38
Ответ принят как подходящий

Опубликованный вами код работает с Компилятор Cameau (что обычно является хорошим показателем того, что он действителен на C++).

Как вы знаете, действительное приведение состоит не более чем из одного определенного пользователем приведения, поэтому возможное решение, о котором я думал, было добавление другого определяемого пользователем приведения путем определения нового типа в шаблоне приведения и наличия статическое утверждение, которое не доступно из новый тип для типа результата (с использованием Boost is_convertible), однако это не делает различий между операторами приведения и конструкторами приведения (ctor с одним аргументом) и позволяет выполнять дополнительные приведения (например, от void* до bool). Я не уверен, что правильный нужно делать различие между операторами приведения и конструкторами приведения, но именно об этом и говорится в вопросе.

После того, как я подумал об этом через пару дней, вы можете просто взять адрес оператора приведения. Это немного легче сказать, чем сделать из-за «волосатого» указателя на член в C++ (мне потребовалось больше времени, чем ожидалось, чтобы понять это правильно). Я не знаю, работает ли это на VS2008, я проверял это только на Cameau.

template< typename Res, typename T>
Res operator_cast( const T& t )
{
    typedef Res (T::*cast_op_t)() const;
    cast_op_t cast_op = &T::operator Res;
    return (t.*cast_op)();
}

Редактировать: У меня была возможность протестировать его на VS2005 и VS2008. Мои выводы отличаются от оригинального плаката.

  • На VS2008 исходная версия, похоже, работает нормально (как и моя).
  • В VS2005 исходная версия приводит к сбою компилятора только при приведении из встроенного типа (например, при приведении int к int) после предоставления ошибки компиляции, которая мне тоже не кажется такой уж плохой, и моя версия, похоже, работает во всех случаях.

Вы пробовали свой шаблон с двумя примерами? VS2008 не скомпилировал тот, который должен был работать, хотя сам шаблон компилировал отлично.

Nick 23.10.2008 02:24

Я просто попробовал, и ваше решение, похоже, работает хорошо. Я получаю ошибку компилятора на VS2005 для встроенных типов в исходном typedef, что отлично. Хорошая идея. :)

Nick 23.10.2008 02:29

Другие вопросы по теме