Есть ли способ приведения только с оператором класса? - PullRequest
3 голосов
/ 16 октября 2008

Случайный вопрос ...

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

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

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

Ответы [ 4 ]

3 голосов
/ 22 октября 2008

Код, который вы опубликовали, работает с компилятором 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) после предоставления ошибки компиляции, которая не кажется мне слишком плохой, и моя версия, кажется, работает во всех случаях.
1 голос
/ 17 октября 2008

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

#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;
}
1 голос
/ 16 октября 2008

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

0 голосов
/ 17 октября 2008

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...