Aki megérti ezt, már ha van aki megérti, eltudná magyarázni?
// TEMPLATE STRUCT SPECIALIZATION equal_to
template<>
struct equal_to<void>
{ // transparent functor for operator==
typedef _Is_trans is_transparent;
template<class _Ty1,
class _Ty2>
_CONST_FUN auto operator()(_Ty1&& _Left, _Ty2&& _Right) const
-> decltype(static_cast<_Ty1&&>(_Left)
== static_cast<_Ty2&&>(_Right))
{ // transparently apply operator== to operands
return (static_cast<_Ty1&&>(_Left)
== static_cast<_Ty2&&>(_Right));
}
};
Hát nem látok mindent, mivel ez nem egy teljes példa. Pl. mi az eredeti template amit specializál, mi az _Is_trans és mi a _CONST_FUN makró? Elmagyarázom a ritkábban használt elemek jelentését, összerakhatod a képet belőle.
Ez egy osztály template specializáció, ami gondolom a void behelyettesítést adja meg egy korábbi template-hez.
A belső függvény pedig perfect forwarding-ot használ. A _Ty1 és _Ty2 template paraméter, ezért a _Ty1&& típusú és _Ty2&& típusú paraméterek forwarding reference-nek számítanak. Azaz képes bal- és jobbreferencia átvételére egyaránt és minden típusra.
A visszatérési érték típusa kikövetkeztetéssel történik (auto kulcsszó a visszetérési érték típusa helyén). A "-> decltype(...)" adja meg a típusát. Pl. a kifejezés bool értékű lehet, ekkor bool&&, bool& és bool lehet a visszatérési érték típusa. Kikerestem a szabályt:
"2) If the argument is any other expression of type T, then
a) if the value category of expression is xvalue, then the decltype specifies T&&
b) if the value category of expression is lvalue, then the decltype specifies T&
c) otherwise, decltype specifies T"
A static_cast meg egyszerűen egy cast, bizonyos megkötéssel. Feltételezem nem ez a gond.
Elég érdekes kódrészlet, nem ártana látni a teljes programot, mert így megvágva nincs sok értelme. Azért végigrágom, hogy mit lehet tudni róla:
template<>
struct equal_to<void>
Ez eleve egy olyan template osztály specializál, amit nem látunk. Ráadásul void típust ad meg, amit értelmes programok ritkán szoktak használni. Inkább tűnik valami közepes minőségű tankönyvi példának.
typedef _Is_trans is_transparent;
Ezt ennyiből nem lehet megmondani, de _ jellel kezdeni osztályt nem valami jó névkonvenció.
template<class _Ty1,
class _Ty2>
Template függvény fog következni
_CONST_FUN
Nincs róla infónk, nagyon remélem, hogy nem a constexpr-re csinált saját makrót.
auto operator()(_Ty1&& _Left, _Ty2&& _Right)
A függvény visszatérési értékét csak később árulja el, a bementi típusok Ty1 és Ty2. A && gondoskodik arról, hogy a bemeneti típus tekintettel legyen a deklarációs típusra, Tehát pla. a const int&& itt is const int&& lesz (rvalue reference).
-> decltype(static_cast<_Ty1&&>(_Left)
== static_cast<_Ty2&&>(_Right))
A visszatérési értéket határozza meg a compiler, úgy, hogy kiszámolja a zárójeles kifejezés értékét. (Ugyanez a kifejezés van a függvény hasában).
Ez C++14-nél teljesen felesleges, (tekintve, hogy a függvény visszatérési értékét decltype-olja), elég lett volna a decltype(auto) az auto helyett, és akkor az egész nyilas dolog nem kell.
return (static_cast<_Ty1&&>(_Left)
== static_cast<_Ty2&&>(_Right))
A static cast felesleges, hisz eleve perfect forwardinggal, tökéletesen típus azonosan vette át a változókat. De ha nem így vette volna át, akkor is hülyeség, emrt önmagára castol. De legalább a futás közbeni teljesítményt nem rontja, csak a fordítás lesz hosszabb.
Így viszont marad egy X == Y szerű kifejezés, tehát a bohóckodás a visszatérési értékkel is felesleges, ez ugyanis csak bool lehet. (Az operator == visszatérési értékét rögzíti a szabvány).
Ezzel a sok maszlaggal le tudod írni azt, hogy
equal_to<void> comparator;
comparator(x,y);
Ami ugyanaz, mintha ennyit írtál volna:
x == y;
Minél többet nézem a kódot, annál inkább úgy gondolom, hogy vagy nem vettem észre valami nagyon alapvető dolgot, vagy ez egy terjengős hülyeség. Lehet, hogy a teljes kontextusban értelmet nyer. Honnan van?
Valóban nem írtam le részletesen honnan van és mégis mire használatos, ezért elnézést (bár ha leírom honnan van nyilván tudjátok mire való).
A kódrészlet a 'xstddef' header fájlból van (STD névtér):
#define _CONST_FUN constexpr (VS 2013 még nem támogatta, így ott gondolom const volt helyette)
A kérdést azért tettem fel, mert szerettem volna megtudni hogyan működnek az ehhez hasonló funkciók és miért úgy ahogy:
std::vector<double> v = {1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,10.10};
double osszeg = 0;
osszeg = std::accumulate(v.cbegin(), v.cend(), osszeg, std::plus<>());
std::cout << osszeg << '\n';
A std::plus bonyolult változata úgy néz ki mint a kérdésemben írt példa, de ezek szerint ha magamnak írok hasonlót teljesen ugyan az a hatás így is:
template<class _Ty = void>
struct plus
{
constexpr _Ty operator()(const _Ty& _Left, const _Ty& _Right) const
{
return (_Left + _Right);
}
};
template<>
struct plus<void>
{
template<class _Ty1, class _Ty2>
constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const
{
return _Left + _Right;
}
};
Illetve a linkelteken kívül, 2 link ami még segített megérteni:
Köszönöm a válaszokat!
>> A static cast felesleges, hisz eleve perfect forwardinggal, tökéletesen típus azonosan vette át a változókat. De ha nem így vette volna át, akkor is hülyeség, emrt önmagára castol. De legalább a futás közbeni teljesítményt nem rontja, csak a fordítás lesz hosszabb.
Nem hülyeség, mert nem megfelelő a paraméter átadás. Pont a belinkelt stack overflow-s kérdésben van részletesen leírva, hogy nem felesleges. Inkább forward<_Ty1>(_Left)-t kellene írni static_cast<_Ty1&&>(_Left) helyett.
Igen, a castot (forwardot) tényleg benéztem, az oda mindenképp kell.
Igazából kíváncsi vagyok, az std ezt mire használja. Felkeltetted az érdeklődésemet.
Kapcsolódó kérdések:
Minden jog fenntartva © 2024, www.gyakorikerdesek.hu
GYIK | Szabályzat | Jogi nyilatkozat | Adatvédelem | Cookie beállítások | WebMinute Kft. | Facebook | Kapcsolat: info(kukac)gyakorikerdesek.hu
Ha kifogással szeretne élni valamely tartalommal kapcsolatban, kérjük jelezze e-mailes elérhetőségünkön!