Я должен реализовать безопасную идиому bool для поддержки компиляторов, которые не имеют explicit
ключевое слово (например, MSVC 2012). Класс, который должен проверяться для bool, моделирует указатель на многие классы, и поэтому он должен быть конвертируемым в эти указатели. Следующий код иллюстрирует идею:
// Uncomment this line to change implementation to 'safe bool'
// #define _COMPILER_NO_EXPLICIT
#if !defined(_COMPILER_NO_EXPLICIT)
#define OPERATOR_BOOL_MYTYPE(...)
#define OPERATOR_BOOL_IMPLEMENTATION(...) \
public: \
explicit operator bool() const noexcept \
{ \
return __VA_ARGS__; \
}
#else
#define OPERATOR_BOOL_MYTYPE(...) \
private: \
void safe_bool() {}; \
typedef __VA_ARGS__ safe_bool_my_type_t; \
typedef void (safe_bool_my_type_t::*safe_bool_t)()
#define OPERATOR_BOOL_IMPLEMENTATION(...) \
public: \
operator safe_bool_t() const noexcept \
{ \
return __VA_ARGS__ ? \
&safe_bool_my_type_t::safe_bool : \
nullptr; \
}
#endifclass Convertible
{
public:
operator int*() const
{ return nullptr; }
operator double*() const
{ return nullptr; }
OPERATOR_BOOL_MYTYPE(Convertible);
OPERATOR_BOOL_IMPLEMENTATION(false);
};int main(void)
{
Convertible a;
if (a)
{
// this 'if' statement introduces compilation error
// in 'safe bool' implementation
}
return 0;
}
Если мы используем explicit operator bool()
Реализация на основе все работает отлично. Проблема на самом деле в неоднозначной конвертируемости в реализации, основанной на «безопасном буле». Как это должно быть решено?
Замечания: Считайте реализацию преобразования bool независимой от других реализаций преобразования указателя. Если это невозможно, дайте мне понять, как реализовать это в зависимом случае, например, если Convertible
оценивается как true, если один из других операторов преобразования возвращает ненулевое значение.
UPD: Я считаю, что есть способ сделать одно неявное преобразование более предпочтительным, чем все остальные.
Ты конечно вам нужно иметь неявное преобразование в другие типы указателей? Если вам это не нужно, проблема исчезнет.
И если вам нужно неявное преобразование к типу указателя, проблема кажется спорным: вам не нужно преобразовать в Bool, потому что преобразование к указателю также даст значение, которое может быть истина проверенная (так же, как обычный сырой указатель ).
Но вы все еще остаетесь с неоднозначным преобразованием из-за того, что у вас есть операторы для обоих int*
а также double*
, Эта часть, вероятно, требует редизайна, потому что не ясно, как можно ожидать, что одно значение будет неявно конвертируемым в несколько не связанных типов указателей.
На самом деле нет хорошего решения. Я нашел тот, который частично отвечает моим требованиям и справился с другими требованиями для ослабления.
В соответствии с http://en.cppreference.com/w/cpp/language/implicit_cast набор и порядок неявных преобразований следующий:
1) ноль или одна стандартная последовательность преобразования
2) ноль или одно пользовательское преобразование
3) ноль или одна стандартная последовательность преобразования
Поскольку оба типа переходов из вопроса определяются пользователем, и оба позволяют дальнейшее стандартное преобразование в bool
Я решил изменить operator int*()
а также operator double*()
функции преобразования в некоторые другие operator Ptr<int>()
а также operator Ptr<double>
где Ptr<T>
является шаблоном класса, который ведет себя так же, как необработанный указатель В частности, он конвертируется в bool, но это не имеет значения, поскольку это второе пользовательское преобразование, и поэтому оно запрещено. Так что единственное преобразование в bool
существует (что из реализации «безопасного bool»).
Недостатком этого решения является то, что клиентский код требуется либо для изменения интерфейсов, либо для явного приведения к необработанному указателю.