2015-04-25 6 views
30

Ich portiere eine C++ 14-constexpr Codebasis von Clang zu den neuesten g ++ - 5.1. Betrachten Sie das folgende reduziert Code-Schnipsel eines home-grown bitset Klasse, die korrekt, da die glückliche Zeit von Clang 3.3 wurde Kompilieren (fast 2 Jahren!)Constexpr ist in der Deklaration der Freundes-Template-Spezialisierung nicht erlaubt?

#include <cstddef> 

template<std::size_t> 
class bitset; 

template<std::size_t N> 
constexpr bool operator==(const bitset<N>& lhs, const bitset<N>& rhs) noexcept; 

template<std::size_t N> 
class bitset 
{ 
    friend constexpr bool operator== <>(const bitset<N>&, const bitset<N>&) noexcept; 
    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <-- error from this piece 
}; 

template<std::size_t N> 
constexpr bool operator==(const bitset<N>& /* lhs */, const bitset<N>& /* rhs */) noexcept 
{ 
    return true; 
} 

int main() {} 

Live example auf Wandbox. Allerdings g ++ - 5.1 und die aktuelle Kofferraumentriegelung einem Fehler geben:

'constexpr' is not allowed in declaration of friend template specialization

Frage: ist dies ein bekannter g ++ Fehler oder Clang nicht auf die neueste Norm konform?

Hinweis: die oben verwendet nur C++ 11-Stil constexpr Funktionen, da es keine Änderungen statt innerhalb operator==, so scheint es einige seltsame Störungen zwischen Vorlagen, Freunde und constexpr.

UPDATE: als bug 65977 auf Bugzilla abgelegt.

+0

Und 4.8.2 beschwert sich über [einen fremden 'Inline'-Spezifizierer] (http://melpon.org/wandbox/permlink/ZNUj29hUVVn5RgJr) ... – Columbo

+0

Ich sehe keine offensichtlichen Antworten darauf, es kann sein hilfreich, um einen GCC-Bug-Bericht zu öffnen, vor allem, da ihre Implementierungsdifferenz zwischen Clang und Gcc ist. Ich sehe keine Mängel, die sich darauf beziehen und obwohl Marcos Antwort vielleicht richtig ist, ist sie mir offensichtlich nicht richtig. –

+0

Ich persönlich hätte das Kopfgeld an Ort und Stelle gelassen, so dass die Antwort mehr Upvotes hätte erhalten können. Es ist eine perfekte Antwort und verdient mehr als 2 Stimmen. –

Antwort

31

GCC ist hier falsch.

Alle Verweise beziehen sich auf N4431, das neueste C++ WD.

[tl; dr: Es gibt einen Unterschied zwischen einer Funktion ist inline (oder genauer gesagt, ist eine Inline-Funktion , wie in 7.1.2/2 definiert ist) und mit dem inline Spezifizierer erklärt wird. Der Spezifizierer constexpr führt eine Inline-Funktion aus, ist aber kein inline-Spezifizierer.]

Spezifizierer werden in Abschnitt 7.1 des C++ - Standards beschrieben und sind ein Element der Grammatik. Daher, wann immer der Standard über einen foo Bezeichner irgendwo auftaucht, bedeutet dies, dass der Bezeichner buchstäblich innerhalb des (Parse Tree des) Quellcodes erschien. Der inline-Spezifizierer ist ein Funktionsspezifizierer, der in Abschnitt 7.1.2 beschrieben wird, und seine Wirkung besteht darin, eine Funktion zu einer Inline-Funktion zu machen. (7.1.2)/2:

A function declaration (8.3.5, 9.3, 11.3) with an inline specifier declares an inline function.

Es gibt zwei weitere Möglichkeiten, um eine Inline-Funktion zu erklären, ohne ein inline Spezifizierer zu verwenden. Man ist in (7.1.2)/3 beschrieben:

A function defined within a class definition is an inline function.

die andere im beschrieben (7.1.5)/1:

constexpr functions and constexpr constructors are implicitly inline (7.1.2).

Keines dieser sagt, dass sich das Verhalten, als ob eine ist inlineSpezifizierer waren vorhanden, lediglich, dass die Funktion eine Inline-Funktion ist.

Warum gibt es diese Regel?

Es gibt eine einfachere Form dieser Regel in (7.1.2)/3:

If the inline specifier is used in a friend declaration, that declaration shall be a definition or the function shall have previously been declared inline.

Der Zweck ist, Freund Erklärungen zu ermöglichen, in den meisten Fällen ignoriert werden - sie sind nicht hinzufügen „neue Informationen“ an die befreundeten Einheit erlaubt, außer in dem speziellen Fall, in dem Sie definieren eine Freund-Funktion. (Dies wiederum ermöglicht eine Implementierung Parsen eine Klassendefinition zu verzögern, bis es „erforderlich“.) So sehen wir auch in (8.3.6)/4:

If a friend declaration specifies a default argument expression, that declaration shall be a definition and shall be the only declaration of the function or function template in the translation unit.

Und das gleiche gilt für eine Erklärung von a Friend-Spezialisierung einer Funktionsvorlage: Wenn sie zusätzliche Informationen hinzufügen könnte, könnten Implementierungen die Analyse der Klassendefinition nicht verzögern.

Nun beachten Sie, dass diese Gründe macht nicht-constexpr gelten: Wenn der constexpr Spezifizierer auf jede Deklaration einer Funktion erscheint, ist es auf jeden Erklärung erscheinen, pro (7.1.5)/1. Da es hier keine "neuen Informationen" gibt, besteht keine Notwendigkeit für eine Einschränkung.

+1

Wunderbare Antwort, danke! Ich werde einen gcc bug report einreichen (3 tatsächlich, da die Bibliotheken DR 2275 und 2301 bezüglich constexpr tuple Funktionalität auch noch nicht in libstdC++ implementiert wurden) – TemplateRex