Есть ли способ использовать только оператор класса?

StackOverflow https://stackoverflow.com/questions/209793

Вопрос

Какой-то случайный вопрос...

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

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<>, но это может сработать, если вы хотите, чтобы он потерпел неудачу (т. е.:компилятор выбирает оператор, которому разрешено преобразование в запрошенный вами тип, когда вы хотели, чтобы произошел сбой, поскольку этот оператор отсутствует).

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

Это было полезно?

Решение

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

Как вы знаете, допустимое приведение состоит не более чем из одного пользовательского приведения, поэтому возможным решением, о котором я думал, было добавление еще одного пользовательского приведения путем определения нового типа в шаблоне приведения и наличия статическое утверждение что приведение нового типа к типу результата недоступно (с использованием повышение is_convertible), однако это не делает различия между операторами приведения и конструкторами приведения (ктор с одним аргументом) и позволяет выполнять дополнительные приведения (например, 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) после предоставления ошибки компиляции, которая мне тоже кажется не такой уж плохой, и моя версия, похоже, работает во всех случаях.

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

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

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

#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;
}

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

/* 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; }

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top