Why should decltype expressions in return types be skewed in a character name?

I recently discovered that decltype expressions are distorted as part of function symbol names when used as return types, and that this can cause unpleasant segmentation errors when dismantling expressions (for example, in debugging sessions) if the expression is too complex.

The first version uses the decltype return type, where the full expression gets garbled ( http://goo.gl/EALubx ):

#include <cstdint> #include <utility> struct A { void bar() const; }; template<typename T> decltype(std::declval<T>().bar()) foo(T const& a); void foo() { A a; return foo(a); } 

Compiled (GCC 5.2.0):

 foo(): sub rsp, 24 lea rdi, [rsp+15] call decltype ((((declval<A>)()).bar)()) foo<A>(A const&) add rsp, 24 ret 

The second version, almost equivalent, where the type of the expression is allowed as part of the optional template parameter ( http://goo.gl/DfQGR5 ):

 #include <cstdint> #include <utility> struct A { void bar() const; }; template<typename T, typename R=decltype(std::declval<T>().bar())> R foo(T const& a); void foo() { A a; return foo(a); } 

Compiled (GCC 5.2.0):

 foo(): sub rsp, 24 lea rdi, [rsp+15] call void foo<A, void>(A const&) add rsp, 24 ret 

I understand that template functions can only be overloaded by their return type, but should the compiler not have to resolve the decltype expression on its own and use the resulting type instead?

Can someone tell me why, or tell me where the C ++ spec states?

+7
c ++ gcc c ++ 11 c ++ 14
source share
1 answer

ANSWER:

As TC explained in the comments, the reason lies in the rules for overloading the template function [temp.over.link]/5-6

For example:

 // #1 template<typename T> decltype(std::declval<T>().bar()) foo(T const& a); // #2 same function as #1, because both are "equivalent": // declared in the same scope, with the same name and // argument/return type expressions are "equivalent" template<typename U> decltype(std::declval<U>().bar()) foo(U const& a); // #3 overloads #1, because argument/return type expressions // may not be resolved to the same value for any given set of T template<typename T> decltype(std::declval<T>().baz()) foo(T const& a); 

It also means that the following is poorly formed:

 // #1 template<typename T> decltype(std::declval<T>().bar(2)) foo(T const& a); // #2 is "functionally equivalent" but not "equivalent" to #1 // because argument/return type expressions are not "equivalent" // but "functionally equivalent": they are resolved to the same value // for any given T template<typename T> decltype(std::declval<T>().bar(1+1)) foo(T const& a); 
+1
source share

All Articles