2015-02-10 17 views
6

Pisząc prostą próbę kompilacji std::array z funkcji generatora, natknąłem się na to: clang ++ 3.5.1 i g ++ 4.9.2 nie zgadzam się, czy funkcja jest constexpr czy nie.gcc i clang nie zgadzają się na funkcję constexpr

kod (jest to C++ 14!):

#include <array> 
#include <utility> 

    template <class T, std::size_t N, class GenType, std::size_t... I> 
    constexpr std::array<T, N> 
make_array_impl (GenType gen, std::index_sequence <I...>) 
{ 
    return {{ gen (I)... }}; 
} 

    template <class T, std::size_t N, class GenType> 
    constexpr std::array<T, N> 
make_array (GenType gen) 
{ 
    return make_array_impl <T, N> (
      gen, 
      std::make_index_sequence <N> {} 
    ); 
} 

    constexpr int 
generator_const (std::size_t /* index */) 
{ 
    return 1; 
} 

    constexpr auto 
a = make_array <int, 3> (generator_const); 

static_assert (a.size() == 3, ""); 
static_assert (a[0] == 1, ""); 
static_assert (a[1] == 1, ""); 
static_assert (a[2] == 1, ""); 

int main() {} 

Kompilacja z g ++:

migou ~ % g++ -std=c++14 ex.cpp 
ex.cpp:28:41: in constexpr expansion of ‘make_array<int, 3ul, int (*)(long unsigned int)>(generator_const)’ 
ex.cpp:18:5: in constexpr expansion of ‘make_array_impl<int, 3ul, int (*)(long unsigned int), {0ul, 1ul, 2ul}>(gen, (std::make_index_sequence<3ul>{}, std::make_index_sequence<3ul>()))’ 
ex.cpp:8:21: error: expression ‘generator_const’ does not designate a constexpr function 
return {{ gen (I)... }}; 

Z brzękiem ++ kompiluje dobrze. Czy mogę iść dalej i wziąć pod uwagę to prawidłowe g ++ 14 (a zatem g ++ podsłuchiwane)?

+2

'g ++' rozluźnia wymagania na 'constexpr' w [' g ++ 'wersja __5__] (https://gc.gnu.org/projects/cxx1y.html), więc może to jest powód. 'clang' wprowadził już N3638 w wersji 3.4. – Zeta

Odpowiedz

2

Jak @Casey słusznie zauważył w komentarzach, nie ma nic mglisty o constexpr -ness części niejawnej konstruktora std::array lub innych agregatów:

12,1 Konstruktorzy [class.ctor]

5 Domyślny konstruktor, który jest domyślny i nie jest zdefiniowany jako usunięty , jest niejawnie zdefiniowany, gdy jest używany odr (3.2) w celu utworzenia obiektu o numerze , jego typ klasy (1.8) lub gdy jest jawnie ustawiony domyślnie po jego pierwsza deklaracja. Niejawnie zdefiniowany domyślny konstruktor wykonuje zestaw inicjalizacji klasy, który byłby wykonywany przez domyślny konstruktor napisany przez użytkownika dla tej klasy bez inicjatora ctor (12.6.2) i pustej instrukcji złożonej. Jeśli ten domyślny konstruktor napisany przez użytkownika byłby źle sformułowany, program jest nieprawidłowo sformatowany. Jeśli ten domyślny konstruktor napisany przez użytkownika spełniałby wymagania konstruktora constexpr (7.1.5), domyślnie zdefiniowany domyślny konstruktor to constexpr. Domyślnie, domyślny konstruktor dla klasy jest niejawnie zdefiniowany, wszystkie domyślne konstruktory nie będące użytkownikami dla swoich klas bazowych i niestatyczne elementy danych będą domyślnie zdefiniowane. [Uwaga: Domyślnie domyślny konstruktor ma specyfikację wyjątku (15.4). Definicja domyślnie oznaczona może zawierać niejawną specyfikację wyjątków, patrz 8.4. -end note]

Zostało to naprawione w najnowszej wersji GCC HEAD 5.0.0 20150217, zobacz to live example i od ponad półtora roku pracuje w Clangu (od wydania IIRC w wersji 3.4, patrz this Q&A).

+0

Problematyczna część to wskaźnik funkcji 'gen', a nie konstruktor tablic. –

+0

@SebastianRedl dlaczego to by było problematyczne? – TemplateRex

1

To jest trochę mgliste. Zasady constexpr C++ 14 Forbid (N3797, 5,19/2 pocisku 2)

o wywołaniu funkcji innej od konstruktora constexpr w dosłownym klasy, w zależności constexpr lub domniemane wywołaniu trywialna destruktora

constexpr nie jest częścią typu, więc wskaźnik funkcji przekazywane do make_array_impl nie jest funkcją constexpr. Z drugiej strony, to odwołuje się do do funkcji constexpr, a ponieważ jest to ocena constexpr, kompilator musi o tym wiedzieć.

Jednak Clang obsługuje ten kod, a GCC 4.9 nie deklaruje zgodności ze swobodnymi funkcjami constexpr, więc zaufałbym Clang w tym przypadku.

+0

Wywołanie adresowane przez ten punktor może być niejawne. Powiedział, że uważam, że połączenie powinno być w porządku. – Columbo

+0

Nie sądzę, że wsparcie dla zrelaksowanego 'constexpr' jest tutaj problemem. Wywołaną funkcją * jest * funkcja 'constexpr', więc powinna ona idealnie odpowiadać nawet regułom' constexpr' C++ 11. Rzeczywiście, [oba clang i g ++ kompilują ten uproszczony przypadek testowy w trybie C++ 11 bez żadnej diagnostyki] (http://coliru.stacked-crooked.com/a/85af35047baa4386). Podejrzewam, że jest to błąd g ++. – Casey

+0

Zobacz moją odpowiedź na standardowy cytat, dlaczego nie powinno być żadnych wątpliwości, że wszystko w kodzie OP jest bona fide "constexpr". – TemplateRex

Powiązane problemy