Подтвердить что ты не робот

С++ зависимый от шаблона аргумент decltype в имени пользователя ABI

Рассмотрим следующую функцию:

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

Фрагмент Min(0, 1) вызывает создание шаблона как Min<int, int>. Как ни странно, искомое имя для Min с g++ и clang для моего кода - _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&&)). Другими словами, выражение, используемое для вывода возвращаемого типа, является частью искаженного имени. Лично я ожидал чего-то чуть более разумного по строкам: _Z3MinIiiET_OS0_OT0_ (aka: int Min<int, int>(int&&, int&&)). Почему это не так?


Похоже, что g++ только выражает выражение decltype в тех случаях, когда это действительно необходимо, так как эти формы являются _Z3Maxii:

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

Ответ 1

Если вы перегружаете функциональные шаблоны, функции, созданные этими шаблонами функций (называемые специализированными функциями), должны быть разными. Следовательно, стандарт С++ указывает, что подпись специализированных шаблонов функций включает в себя подпись шаблона функции, из которого была создана специализация.

В противном случае, если оба шаблона будут создавать экземпляры функций, имеющих один и тот же тип функции, они будут сталкиваться.

Ответ 2

gcc использует "Italium С++ ABI" для mangling, и он указывает, что

Если выражение операнда decltype не зависит от инстанцирования, тогда результирующий тип кодируется напрямую. Например:

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

Третий пример - это уменьшенная версия OP, которая также кодирует все выражение напрямую, потому что оно зависит от экземпляра. Активация зависит от:

Выражение является зависимым от экземпляра, если оно зависит от типа или зависит от значения или имеет подвыражение, зависящее от типа или зависящее от стоимости. Например, если p является зависимым от типа идентификатором, выражение sizeof(sizeof(p)) не зависит от типа и не зависит от значения, но оно зависит от экземпляра (и может оказаться недопустимым, если после подстановки аргументов шаблона p оказывается неполным). Аналогично, тип, выраженный в исходном коде, является зависимым от экземпляра, если исходная форма включает в себя выражение, зависящее от экземпляра. Например, форма типа double[sizeof(sizeof(p))]p зависимым от типа идентификатором) является зависимой от экземпляра.

Ключевым моментом является то, что выражения, зависящие от экземпляра "могут оказаться недействительными после замены", что, вероятно, является причиной того, что они оставлены в неоцененной форме в mangling.