Написал арифметическую оболочку, которая могла бы помочь обнаружить ошибки overflow/underflow, однако застряла с довольно коварной проблемой в процессе.Изменение типа возвращаемого шаблона, похоже, влияет на разрешение перегрузки.
Предположим, что у нас есть класс, который обрабатывает все, что может вызвать переполнение через некоторые перегруженные операторы и неявно приписывается базовому типу для всего остального. Этот пример содержит только бинарный оператор плюс:
template<typename T_>
class Wrapper
{
public:
Wrapper(T_ val_) : m_value(val_) { } // converting constructor
operator T_(void) const { return m_value; } // underlying type conversion
// some other methods
// binary plus operators:
template<typename U_>
const Wrapper<decltype(T_() + U_())> operator +(U_ val_) const
{
// supposed to handle 'Wrapped + Unwrapped' case
return m_value + val_;
}
template<typename U_>
const Wrapper<decltype(T_() + U_())> operator +(Wrapper<U_> other_) const
{
// supposed to handle 'Wrapped + Wrapped' case
return m_value + other_.m_value;
}
template<typename U0_, typename U1_>
friend const Wrapper<decltype(U0_() + U1_())> operator +(U0_ val_, Wrapper<U1_> wrapper_)
{
// supposed to handle 'Unwrapped + Wrapped' case
return val_ + wrapper_.m_value;
}
private:
T_ m_value;
};
Это (если я не пропустить что-то в то время как приклеивая его здесь) отлично компилируется и работает , как ожидается, в подобных ситуациях (каждый возможный один из них, в основном) :
Wrapper<int> val = 3.14f;
::std::cout << val + 42 << ::std::endl; // Wrapped + Unwrapped
::std::cout << 42 + val << ::std::endl; // Unwrapped + Wrapped
::std::cout << val + val << ::std::endl; // Wrapped + Wrapped
Однако всякий раз, когда я пытаюсь сделать псевдоним для decltype(...)
части либо «Облаченный + развернутого» или «развернутого + обернутый», например, как это:
template<typename T0_, typename T1_>
struct Result
{
typedef decltype(T0_() + T1_()) Type;
};
template<typename T_>
class Wrapper
{
//...
template<typename U_>
const Wrapper<typename Result<T_, U_>::Type> operator +(U_ val_) const
//...
template<typename U0_, typename U1_>
friend const Wrapper<typename Result<U0_, U1_>::Type> operator +(U0_ val_, Wrapper<U1_> wrapper_)
//...
};
Пример «Обернутый + обернутый» не хочет компилироваться, потому что разрешение перегрузки меняется на нежелательный вариант. Он выдает ошибку о недоступности конструктора по умолчанию для Wrapper<int>
, называя попытку использовать либо «Обернутый + Unwrapped», либо «Unwrapped + Wrapped», оба из которых не подходят для правильной обработки рассматриваемого случая.
И это меня смущает, поскольку изменение типа возврата приводит к изменению поведения разрешения перегрузки. По достоинству оценят любые советы по этому вопросу.
Нежелательные Перегрузки были SFINAE'd прочь; теперь это не так, потому что потенциально недопустимое выражение было перенесено в определение «Результат» и вне контекста. –
Итак, я был не в порядке, чтобы предположить, что вариант «Обернутый + обернутый» будет считаться более подходящим для разрешения перегрузки в такой ситуации. Возьмите за ответ. – so100217
Это может быть лучшая перегрузка (из-за частичного заказа и т. Д.), Но вы даже не добираетесь туда: вы вызываете жесткую ошибку, пытаясь сформировать набор кандидатов. –