С++ зависимый от шаблона аргумент 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)
Ответы
Ответ 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.