Safe bool неоднозначность многократных преобразований

Я должен реализовать безопасную идиому 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: Я считаю, что есть способ сделать одно неявное преобразование более предпочтительным, чем все остальные.

0

Решение

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

И если вам нужно неявное преобразование к типу указателя, проблема кажется спорным: вам не нужно преобразовать в Bool, потому что преобразование к указателю также даст значение, которое может быть истина проверенная (так же, как обычный сырой указатель ).

Но вы все еще остаетесь с неоднозначным преобразованием из-за того, что у вас есть операторы для обоих int* а также double*, Эта часть, вероятно, требует редизайна, потому что не ясно, как можно ожидать, что одно значение будет неявно конвертируемым в несколько не связанных типов указателей.

1

Другие решения

На самом деле нет хорошего решения. Я нашел тот, который частично отвечает моим требованиям и справился с другими требованиями для ослабления.

В соответствии с 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»).

Недостатком этого решения является то, что клиентский код требуется либо для изменения интерфейсов, либо для явного приведения к необработанному указателю.

0

По вопросам рекламы [email protected]