2016-01-06 7 views
7

Ich habe vor kurzem herausgefunden, dass declltype Ausdrücke als Teil der Funktionen Symbolnamen verstümmelt sind, wenn sie als Rückgabetypen verwendet werden, und dies kann die Ursache für böse Segmentierungsfehler beim Entmelden der Ausdrücke sein (in Debugging-Sitzungen zum Beispiel), wenn Ausdruck ist zu komplex.Warum Deklinationsausdrücke in Rückgabetypen müssen im Symbolnamen manipuliert werden?

Die erste Version, in der Funktion Rückgabetyp mit decltype, wo der volle Ausdruck (http://goo.gl/EALubx) verstümmelt wird:

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

auf (GCC 5.2.0) zusammengestellt:

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

Die zweite Version, fast gleichwertig, wobei der Ausdruckstyp als Teil eines zusätzlichen Vorlagenparameters aufgelöst wird (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); } 

auf (GCC 5.2.0) zusammengestellt:

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

Ich verstehe, dass nur bei ihrer Rückkehr Art Template-Funktionen überlastet werden können, soll aber nicht der Compiler der Lage sein, den decltype Ausdruck auf seinem eigenen zu lösen und mangle stattdessen den resultierenden Typ?

Kann mir jemand sagen warum, oder zeigen Sie mir, wo in der C++ - Spezifikation angegeben ist?

+1

Ich sehe nichts falsch daran, es ist nur der Name der Funktion. Eigentlich wäre ein aufgelöster Rückgabetyp sehr viel verwirrender ... –

+0

Ich glaube, dass die Unterstützung von willkürlichen komplexen Ausdrücken in verfälschten Namen nicht trivial ist und der Implementierung des Umsetzers höhere Einschränkungen auferlegt. Während ich zustimme, dass es ein Implementierungsproblem ist, zum Beispiel, GDB segfaults, wenn die Ausdrücke zu komplex sind. –

+0

Nun, der Compiler * könnte auch die aufgelöste Information ausgeben und anderen Tools in der Kette helfen. Mein Rat, sei * extrem * geduldig ... (https://sourceware.org/bugzilla/show_bug.cgi?id=14441) –

Antwort

1

ANTWORT:

Wie T.C. in den Kommentaren erklärt, liegt der Grund in der Überlast Template-Funktion Regeln [temp.over.link]/5-6

Zum Beispiel:

// #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); 

Dies bedeutet auch, dass die folgenden ist schlecht gebildet:

// #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); 
Verwandte Themen