Pytanie C ++ zależny od typu szablonu-decltype w zniekształconej nazwie ABI


Rozważ następującą funkcję:

template <typename A, typename B>
auto Min(A&& a, B&& b)
        -> decltype(a < b ? std::forward<A>(a) : std::forward<B>(b))
{
    return a < b ? std::forward<A>(a) : std::forward<B>(b);
}

Fragment Min(0, 1) powoduje, że szablon jest tworzony jako Min<int, int>. O dziwo, zmasakrowane imię dla Min z g ++ i clang dla mojego kodu jest _Z3MinIiiEDTqultfp_fp0_cl7forwardIT_Efp_Ecl7forwardIT0_Efp0_EEOS0_OS1_ (znany jako: decltype (({parm#1}<{parm#2})?((forward<int>)({parm#1})) : ((forward<int>)({parm#2}))) Min<int, int>(int&&, int&&)). Innymi słowy, wyrażenie używane do wyprowadzenia typu zwrotu jest częścią zmasakrowanej nazwy. Osobiście spodziewałam się czegoś nieco bardziej przy zdrowych zmysłach na wzór: _Z3MinIiiET_OS0_OT0_ (znany jako: int Min<int, int>(int&&, int&&)). Dlaczego tak nie jest?


Wygląda na to, że g ++ stawia tylko decltype wyrażenie w przypadkach, gdy jest to rzeczywiście potrzebne, ponieważ te formy są oba _Z3Maxii:

  • auto Max(int x, int y) -> int
  • auto Max(int x, int y) -> decltype(0)

12
2017-11-08 18:01


pochodzenie


Dlaczego to ma znaczenie? - Praetorian
Ciekawość, głównie. Wydaje się bardzo dziwną decyzją, aby powiedzieć "Zamierzam zakodować całe wyrażenie w zniekształconą nazwę" zamiast "Zamierzam rozwiązać typ zwrotu i użyć tego". Oznacza to, że GCC i Clang musiały poświęcić wiele wysiłku, aby zdecydować się na wspólny system wyłudzania wyrażeń zamiast po prostu trzymać się typów. Musi być powód dla tej decyzji i jestem pewien, że ktoś wie dlaczego. - Travis Gockel


Odpowiedzi:


W przypadku przeciążenia szablonów funkcji funkcje utworzone przez te szablony funkcji (zwane specjalizacją szablonu funkcji) muszą być różne. Stąd Standard C ++ określa, że ​​sygnatury specjalizacji szablonów funkcji zawierają sygnaturę szablonu funkcji, z którego została wygenerowana specjalizacja.

W przeciwnym razie, gdyby oba szablony tworzyły instancje o tym samym typie funkcji, kolidowałyby ze sobą.


2
2017-11-08 19:51



Czy istnieje przypadek, w którym wymieniono dwie funkcje szablonu f które różnią się tylko typem zwrotnym, który nie jest nieprawidłowym przeciążeniem? - Travis Gockel
@travis często jest to robione podczas wprowadzania wyrażenia SFINAE w typie zwracanym. - Johannes Schaub - litb
Różnica niekoniecznie musi być typem zwrotu. Może to być również typ parametru. Na przykład template<typename T> void f(const T*); template<typename T> void f(T*);. Tworzenie instancji zarówno z const int daje dwie funkcje tego samego typu. - Johannes Schaub - litb


gcc używa "Italium C ++ ABI" do skrępowaniai to określa

Jeśli operand wyrażenie decltype nie jest zależne od instancji następnie wynikowy typ jest kodowany bezpośrednio. Na przykład:

      int x;
      template<class T> auto f(T p)->decltype(x);
        // The return type in the mangling of the template signature
        // is encoded as "i".
      template<class T> auto f(T p)->decltype(p);
        // The return type in the mangling of the template signature
        // is encoded as "Dtfp_E".
      void g(int);
      template<class T> auto f(T p)->decltype(g(p));
        // The return type in the mangling of the template signature
        // is encoded as "DTcl1gfp_E".

Trzeci przykład to zredukowana wersja OP, która również bezpośrednio koduje całe wyrażenie, ponieważ jest zależne od instancji. Zależne od instancji jest zdefiniowany jako:

Wyrażenie to zależne od instancji jeśli jest zależny od typu lub zależy od wartości lub ma podwyrażenie zależne od typu lub od wartości. Na przykład, jeśli p to identyfikator zależny od typu, wyrażenie sizeof(sizeof(p)) nie zależy ani od typu, ani od wartości, ale jest zależne od instancji (i może okazać się nieprawidłowe jeśli po zastąpieniu argumentów szablonu p okazuje się mieć niekompletny typ). Podobnie, typ wyrażony w kodzie źródłowym jest zależny od instancji, jeśli forma źródłowa zawiera znak zależne od instancji wyrażenie. Na przykład formularz typu double[sizeof(sizeof(p))] (z p identyfikator zależny od typu) zależne od instancji.

Kluczową kwestią jest to, że wyrażeń zależnych od wyrażeń "może okazać się nieważne po substytucji", co jest prawdopodobnie powodem, dla którego są one pozostawione w unevaluated formie w the mangling.


4
2017-11-08 19:12



Czy to nie ma znaczenia? O ile go rozumiałem, pytanie brzmiało, dlaczego specjalizacja zawiera kodowanie dołączonego do niego szablonu, a nie dlaczego kodowanie skojarzonego szablonu ma wbudowany typ decltype (na który odpowiedź będzie odpowiedzią). Nawet jeśli sprawisz, że typ zwrotu szablonu będzie niezależny, powiedz template<typename T, typename U> auto Min(T&&, U&&) -> int { }, specjalizacja nadal zawiera podpis dołączonego szablonu. - Johannes Schaub - litb
Nadal nie jestem pewien czemu to konieczne. W trzecim przykładzie, gdzie T jest int, dlaczego nie po prostu rozwiązać typ zwracany do void i uderz v w zniekształconej formie podczas tworzenia instancji f<int>? W przypadkach, w których podstawienie jest nieważne dla danego typu, nie obchodzi go nazwa przekłamana, ponieważ nie jest to funkcja wywoływalna. - Travis Gockel