Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ template-argument dependent decltype in ABI mangled name

Consider the following function:

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);
}

The fragment Min(0, 1) causes the template to be instantiated as Min<int, int>. Strangely, the mangled name for Min with g++ and clang for my code is _Z3MinIiiEDTqultfp_fp0_cl7forwardIT_Efp_Ecl7forwardIT0_Efp0_EEOS0_OS1_ (aka: decltype (({parm#1}<{parm#2})?((forward<int>)({parm#1})) : ((forward<int>)({parm#2}))) Min<int, int>(int&&, int&&)). In other words, the expression used to deduce the return type is part of the mangled name. Personally, I expected something slightly more sane along the lines of: _Z3MinIiiET_OS0_OT0_ (aka: int Min<int, int>(int&&, int&&)). Why is this not the case?


It seems that g++ only puts the decltype expression in cases where it is actually needed, as these forms are both _Z3Maxii:

  • auto Max(int x, int y) -> int
  • auto Max(int x, int y) -> decltype(0)
like image 980
Travis Gockel Avatar asked Nov 08 '12 18:11

Travis Gockel


2 Answers

gcc is using the "Italium C++ ABI" for mangling, and it specifies that

If the operand expression of decltype is not instantiation-dependent then the resulting type is encoded directly. For example:

      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".

The 3rd example is a reduced version of OP's, which also encode the whole expression directly, because it is instantiation-dependent. Instantiation-dependent is defined as:

An expression is instantiation-dependent if it is type-dependent or value-dependent, or it has a subexpression that is type-dependent or value-dependent. For example, if p is a type-dependent identifier, the expression sizeof(sizeof(p)) is neither type-dependent, nor value-dependent, but it is instantiation-dependent (and could turn out to be invalid if after substitution of template arguments p turns out to have an incomplete type). Similarly, a type expressed in source code is instantiation-dependent if the source form includes an instantiation-dependent expression. For example, the type form double[sizeof(sizeof(p))] (with p a type dependent identifier) is instantiation-dependent.

The key point is that instantiation-dependent expressions "could turn out to be invalid after substitution", which is likely the reason they are left in the unevaluated form in the mangling.

like image 186
kennytm Avatar answered Sep 23 '22 18:09

kennytm


If you overload function templates, the functions produced by these function templates (called a function template specialization) need to be different. Hence the C++ Standard specifies that the signature of function template specializations include the signature of the function template from which the specialization was generated.

Otherwise if both templates would instantiate functions that have the same function type, they would clash.

like image 4
Johannes Schaub - litb Avatar answered Sep 20 '22 18:09

Johannes Schaub - litb