Bir diziyi constexpr yapıcısında başlatmak meşru mu?


11

Aşağıdaki kod yasal mı?

template <int N>
class foo {
public:
    constexpr foo()
    {
        for (int i = 0; i < N; ++i) {
            v_[i] = i;
        }
    }

private:
    int v_[N];
};

constexpr foo<5> bar;

Clang kabul eder, ancak GCC ve MSVC bunu reddeder.

GCC'nin hatası:

main.cpp:15:18: error: 'constexpr foo<N>::foo() [with int N = 5]' called in a constant expression
   15 | constexpr foo<5> bar;
      |                  ^~~
main.cpp:4:15: note: 'constexpr foo<N>::foo() [with int N = 5]' is not usable as a 'constexpr' function because:
    4 |     constexpr foo()
      |               ^~~
main.cpp:4:15: error: member 'foo<5>::v_' must be initialized by mem-initializer in 'constexpr' constructor
main.cpp:12:9: note: declared here
   12 |     int v_[N];
      |         ^~

Bu tür bir kod tamam olsaydı, index_sequences birkaç kullanımı kesebilir .


1
Gcc10 da kabul eder.
songyuanyao

hatayı MSVC'den kopyalayabilir misiniz?
max66

... ve GCC de.
Evg

1
@songyuanyao - g ++ 10 C ++ 20 derlemesini kabul eder; C ++ 17 veya daha eski derlemeyi reddediyor; nokta _v, C ++ 17'ye kadar başlatma listesinde başlatılması gerektiği anlaşılıyor . Belki C ++ 20'de bir şey değiştirildi.
max66

2
@Evg Bu gerçekten ilginç, çünkü Clang'ın statik farkındalık süresi nesnesinin "tamam, bu nesne varsayılan olarak başlatılmış olabilir, ancak intüyesinden gelen okumaların hiçbir zaman tanımsız davranışları olmayacağını söylemek için sıfırlandığı" farkındalığını "kullanmasını önerebilir. ". GCC'nin bunu yapmamasının uyumlu olup olmadığını merak ediyorum ...
Orbit'teki Hafiflik Yarışları

Yanıtlar:


13

C ++ 20'ye kadar bir constexprbağlamda önemsiz varsayılan başlatma yasaklandı .

Sanırım, varsayılan olarak başlatılan ilkellerden "yanlışlıkla" okunmasının kolay olması, programınıza tanımsız davranışlar veren bir davranış ve tanımlanmamış davranışları olan ifadelerin doğrudan constexpr( ref ) olması yasaktır . Dil artık genişletildi, böylece bir derleyici böyle bir okumanın yapılıp yapılmadığını kontrol etmeli ve eğer değilse, varsayılan başlatma kabul edilmelidir. Derleyici için biraz daha fazla iş, ama (gördüğünüz gibi!) Programcı için önemli faydaları var.

Bu makale tanımsız davranışların çağrılmasına izin vermemeye devam ederken, bağlam bağlamlarında önemsiz varsayılan yapılandırılabilir türler için varsayılan başlatmaya izin verilmesini önermektedir. Kısacası, başlatılmamış değerler okunmadığı sürece, bu tür durumlara hem yığın hem de yığın tahsis senaryolarında bağlamda izin verilmelidir.

C ++ 20'den beri olduğu v_gibi "başlatılmamış" bırakmak yasaldır . Sonra tüm element değerlerini atamaya devam ettiniz, bu harika.


4
@ max66 Ben de! Tek yaptığım Wikipedia'daki C ++ 20 değişiklik listesini taramak, alakalı bir şey bulmak constexprve bağlantılı teklifi gözden kaçırmaktı;)
Orbit'teki Hafiflik Yarışları

3
Kötü kısmı 20 yıldan fazla C ++ kullanıyorum olmasıdır. Her gün yeni bir şey öğrenirsem ... ya da kötü bir programcıysam ya da C ++ çok karmaşık hale gelir.
max66

5
@ max66 Neredeyse kesinlikle ikincisi. Ayrıca her iki yılda bir sürekli değişmeye devam etmesi onu hızlı hareket eden bir hedef haline getiriyor. Buna kim ayak uydurabilir ?! Derleyiciler bile buna uymuyor.
Orbit'te Hafiflik Yarışları

@ max66 Bu yazı akla geliyor: Vasa'yı hatırla!
Evg

@Evg Vay canına, o kağıt beni (DEMİR) geçti. Bulun!
Orbit'te Hafiflik Yarışları
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.