2015-04-25 8 views
30

Przekazuję kodowanie C++ 14- constexpr z Clang do najnowszego g ++ - 5.1. Rozważmy następujący fragment kodu zmniejszone o rodzimych bitset klasy, która została opracowującym właściwie od czasów cudownych Clang 3.3 (prawie 2 lat!)Constexpr jest niedozwolone w ogłoszeniu o specjalizacji szablonu przyjaciela?

#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 na Wandbox. Jednakże, g ++ - 5.1 i obecny uwolnienie bagażnik daje błąd:

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

Pytanie: jest to znany bug lub g ++ jest Clang nie zgodny z najnowszym standardem?

Uwaga: powyżej wykorzystuje tylko C++ 11 stylem constexpr możliwości, ponieważ nie istnieją żadne zmiany zachodzące wewnątrz operator==, więc wydaje się trochę dziwne zakłócenia między szablonami, przyjaciół i constexpr.

UPDATE: złożony jako bug 65977 na Bugzilli.

+0

I 4.8.2 narzeka na [nieistotny specyfikator 'inline'] (http://melpon.org/wandbox/permlink/ZNUj29hUVVn5RgJr) ... – Columbo

+0

Nie widzę żadnych oczywistych odpowiedzi na to, może być pomocne w otworzeniu raportu o błędzie gcc, zwłaszcza, że ​​jest to różnica w implementacji między clangiem i gcc. Nie widzę żadnych wad, które się z tym wiążą i chociaż odpowiedź Marco jest prawdopodobnie poprawna, nie jest to oczywiście dla mnie poprawne. –

+0

Osobiście zostawiłbym nagrodę w miejscu, więc odpowiedź mogłaby otrzymać więcej głosów na głos. To idealna odpowiedź i zasługuje na więcej niż 2 głosy. –

Odpowiedz

31

GCC jest tutaj błędne.

Wszystkie odniesienia do N4431, najnowszego C++ WD.

[tl; dr: Jest to różnica między funkcją jest rolki (lub dokładniej, jest funkcją rolki, jak zdefiniowano w 7.1.2/2) i jest uznane za inline specyfikacją. Specyfikator constexpr pełni funkcję inline, ale nie jest specyfikatorem inline.]

Specyfikatory są opisane w podrozdziale 7.1 standardu C++ i są elementem gramatyki. Dlatego zawsze, gdy standard mówi gdzieś o specyfikatorze foo, oznacza to, że specyfikator dosłownie pojawił się w drzewie kodu (drzewo parsera). Specyfikator inline jest specyfikatorem funkcji , opisanym w podrozdziale 7.1.2, a jego efektem jest uczynienie z funkcji funkcji inline. (7.1.2)/2:

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

Istnieją dwa inne sposoby zadeklarować funkcji inline, bez użycia inline specyfikator. Jednym z nich jest opisana w (7.1.2)/3:

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

Drugi jest opisana w (7.1.5)/1:

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

Żadna z nich mówi, że zachowanie jest jak gdyby inlineSpecifier były obecne, tylko że funkcja jest funkcją inline.

Dlaczego więc ta reguła istnieje?

Istnieje prostsza forma tej reguły (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.

Celem tego jest umożliwienie deklaracji znajomego, aby być ignorowane w większości przypadków - nie wolno dodawać „nowe informacje” z zaprzyjaźnionej jednostki, z wyjątkiem przypadku, gdy specjalny definiują funkcję przyjaciela. (To z kolei pozwala na wdrożenie opóźnia parsowania definicji klasy, dopóki nie jest „konieczna”.) Tak więc widzimy, w (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.

I to samo odnosi się do deklaracja specjalizacja znajomego szablonu funkcji: gdyby mógł dodać dodatkowe informacje, implementacje nie mogły opóźnić analizy definicji klasy.

Teraz należy pamiętać, że to uzasadnienie nie nie dotyczą constexpr: jeśli na każdej deklaracji funkcji pojawi się constexpr specifier, musi pojawić się na każdą deklarację Per (7.1.5)/1. Ponieważ nie ma tu "nowych informacji", nie ma potrzeby wprowadzania ograniczeń.

+1

Wspaniała odpowiedź, dzięki! Złożę raport o błędzie gcc (w rzeczywistości 3, ponieważ biblioteka DR 2275 i 2301, dotycząca funkcji krępującej constexpr, również nie została jeszcze zaimplementowana w libstdC++) – TemplateRex