Рассмотрим простой класс int Wrapper
с перегруженным умножением operator*=
и operator*
. Для "перегрузки" старого стиля можно определить operator*
в терминах operator*=
, и есть даже такие библиотеки, как Boost. Операторы и его современное воплощение df.operators by @DanielFrey, которые уменьшают шаблон для вас.
Однако для вычислений времени компиляции с использованием нового С++ 11 constexpr
это удобство исчезает. A constexpr operator*
не может вызывать operator*=
, потому что последний изменяет его (неявный) левый аргумент. Кроме того, нет перегрузки на constexpr, поэтому добавление дополнительного constexpr operator*
к существующему operator*
приводит к двусмысленности разрешения перегрузки.
Мой текущий подход:
#include <iostream>
struct Wrap
{
int value;
Wrap& operator*=(Wrap const& rhs)
{ value *= rhs.value; return *this; }
// need to comment this function because of overloading ambiguity with the constexpr version
// friend Wrap operator*(Wrap const& lhs, Wrap const& rhs)
// { return Wrap { lhs } *= rhs; }
friend constexpr Wrap operator*(Wrap const& lhs, Wrap const& rhs)
{ return { lhs.value * rhs.value }; }
};
constexpr Wrap factorial(int n)
{
return n? factorial(n - 1) * Wrap { n } : Wrap { 1 };
}
// want to be able to statically initialize these arrays
struct Hold
{
static constexpr Wrap Int[] = { factorial(0), factorial(1), factorial(2), factorial(3) };
};
int main()
{
std::cout << Hold::Int[3].value << "\n"; // 6
auto w = Wrap { 2 };
w *= Wrap { 3 };
std::cout << w.value << "\n"; // 6
}
Живой вывод здесь. Мои проблемы с этим:
- дублирование логики умножения как в
operator*=
, так иoperator*
вместоoperator*
выражается черезoperator*=
- следовательно, Boost.Operators больше не работает, чтобы уменьшить шаблон для записи многих других арифметических операторов.
Вопрос: это рекомендуемый способ С++ 11 иметь как время выполнения operator*=
, так и смешанное время выполнения/время компиляции constexpr operator*
? Изменяет ли С++ 14 что-либо здесь, например? уменьшить логическое дублирование?
ОБНОВЛЕНИЕ. Ответ от @AndyProwl принимается как идиоматический, но, согласно предложению @DyP, на С++ 11 можно уменьшить дублирование логики за счет дополнительного назначения и контр- интуитивно понятный стиль
// define operator*= in terms of operator*
Wrap& operator*=(Wrap const& rhs)
{ *this = *this * rhs; return *this; }