Rozważ klasę prostą int Wrapper
z przeciążonym mnożeniem operator*=
i operator*
. W przypadku "przeciążania operatorów" w starym stylu można zdefiniować operator*
pod względem operator*=
, a istnieją nawet biblioteki takie jak Boost.Operators i jego nowoczesne wcielenie df.operators autorstwa @DanielFrey, które zmniejszają dla Ciebie podstawę.Wytyczne dotyczące przeciążania operatora constexpr?
Jednak w przypadku obliczeń kompilacji przy użyciu nowego C++ 11 constexpr
wygoda ta znika. A constexpr operator*
nie może wywołać operator*=
, ponieważ ten drugi modyfikuje jego (niejawny) lewy argument. Ponadto istnieje no overloading on constexpr, więc dodanie dodatkowej constexpr operator*
do istniejącego operator*
powoduje niejednoznaczność rozdzielczości przeciążenia.
Moje obecne podejście jest:
#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
}
Live output here. Moje problemy z tym są:
- powielanie logiki mnożenia zarówno
operator*=
ioperator*
zamiastoperator*
wyrażone w kategoriachoperator*=
- Stąd Boost.Operators nie działa w celu zmniejszenia Gotowa do pisania wielu inne operatory arytmetyczne
Pytanie: jest to zalecana C++ 11 sposobem posiadania zarówno run-time operator*=
i mieszane run-time/w czasie kompilacji constexpr operator*
? Czy C++ 14 zmienia wszystko tutaj, na przykład zmniejszyć powielanie logiki?
UPDATE: Odpowiedź przez @AndyProwl akceptuje idiomatyczne ale jak za sugestią @DyP w C++ 11 jeden mógłby ograniczenie powielania logiki kosztem dodatkowego przydziału i intuicyjne stylu
// define operator*= in terms of operator*
Wrap& operator*=(Wrap const& rhs)
{ *this = *this * rhs; return *this; }
Jaki jest twój pożytek z "normalnego" przeciążenia, jeśli może to być "constexpr"? IIRC 'constexpr' będzie wdzięcznie degradować do _runtime execution_ in non -constexpr' kontekście. – sehe
@she nie możesz mieć 'operatora constexpr * =', więc 'operator constexpr *' nie może tego wywołać, a zamiast tego musi duplikować logikę wyodrębniania pól itp. – TemplateRex
Ach, zaczynam widzieć twoje prawdziwe pytanie. Nie jest *** o tym, że nie ma przeciążenia non-'constexpr' (nie potrzebujesz ich!), Ale raczej o braku możliwości udostępniania kodu, ponieważ '* =' nie może być 'constexpr'.Dobrze, że już + w dobrej wierze :) – sehe