C ++ 17 satır içi değişkenleri tanıtır
C ++ 17 constexpr static
, odr kullanılıyorsa hat dışı tanım gerektiren üye değişkenler için bu sorunu giderir . C ++ 17 öncesi ayrıntılar için bu cevabın ikinci yarısına bakın.
Teklif P0386 Satır İçi Değişkenler , inline
belirteci değişkenlere uygulama yeteneği sunar . Bu durumda özellikle constexpr
ima inline
statik üye değişkenler için. Teklif şöyle diyor:
Satır içi belirtici değişkenlere olduğu kadar işlevlere de uygulanabilir. Satır içi bildirilen bir değişken, satır içi bildirilen bir işlevle aynı anlambilime sahiptir: aynı, birden çok çeviri biriminde tanımlanabilir, tek kullanımlık olduğu her çeviri biriminde tanımlanmalıdır ve programın davranışı sanki tam olarak bir değişken var.
ve değiştirilmiş [basic.def] p2:
Bir beyan, bir tanım olmadıkça
...
- sınıf tanımının dışında statik bir veri üyesi bildirir ve değişken sınıf içinde constexpr belirteci ile tanımlanır (bu kullanım kullanımdan kaldırılır; bkz. [depr.static_constexpr]),
...
ve [depr.static_constexpr] ekleyin :
Önceki C ++ Uluslararası Standartları ile uyumluluk için, bir constexpr statik veri üyesi, başlatıcı olmadan sınıf dışında gereksiz yere yeniden bildirilebilir. Bu kullanım kullanımdan kaldırıldı. [ Misal:
struct A {
static constexpr int n = 5; // definition (declaration in C++ 2014)
};
constexpr int A::n; // redundant declaration (definition in C++ 2014)
- son örnek]
C ++ 14 ve öncesi
C ++ 03'te, yalnızca const integralleri veya const numaralandırma türleri için sınıf içi başlatıcılar sağlamamıza izin verildi, bunu kullanarak C ++ 11'de değişmez türlereconstexpr
genişletildi .
C ++ 11, biz statik bir ad kapsamı tanımını sağlamak gerekmez constexpr
Değilse üyesi ODR kullanılan , biz taslak C ++ 11 standart bölümünden görebilirsiniz 9.4.2
[class.static.data] diyor ( benim ön plana çıkıyor ):
[...] Değişmez türde bir statik veri üyesi, constexpr belirleyicisi ile sınıf tanımında bildirilebilir; öyleyse, bildirimi, atama ifadesi olan her başlatıcı yan tümcesinin sabit bir ifade olduğu bir küme ayracı veya eşit başlatıcısı belirtmelidir. [Not: Bu iki durumda da üye sabit ifadelerle görünebilir. —End not]
Üye, programda odr (3.2) kullanılıyorsa ve ad alanı kapsam tanımlamasında bir başlatıcı bulunmayacaksa yine de bir ad alanı kapsamında tanımlanmalıdır.
O zaman soru şu, burada baz
odr kullanılıyor :
std::string str(baz);
ve cevap evet , bu yüzden bir isim alanı kapsamı tanımına da ihtiyacımız var.
Peki bir değişkenin odr kullanılıp kullanılmadığını nasıl belirleyebiliriz ? 3.2
[Basic.def.odr] bölümündeki orijinal C ++ 11 ifadeleri şöyle diyor:
Bir ifade, değerlendirilmemiş bir işlenen (Madde 5) veya bunun bir alt ifadesi olmadıkça potansiyel olarak değerlendirilir. Adı, potansiyel olarak değerlendirilen bir ifade olarak görünen bir değişken, sabit bir ifadede (5.19) görünme gereksinimlerini karşılayan
bir nesne olmadığı ve lvalue-rvalue dönüşümü (4.1) hemen uygulanmadığı sürece odr kullanılır .
Bu yüzden baz
, bir verim yapar sabit ifade ancak lvalue-için-rvalue bu nedeniyle uygun değildir çünkü hemen uygulanmaz dönüşüm baz
bir dizisi olan. Bu, şu 4.1
konudaki [dönş. Lval] bölümünde ele alınmıştır :
İşlevsel olmayan, T tipi olmayan bir glvalue (3.10) bir ön değere dönüştürülebilir.53 [...]
Ne uygulanan dizi-to-pointer dönüşümü .
[Basic.def.odr] ifadesi, Bazı durumlar bu ifadede yer almadığı için Hata Raporu 712 nedeniyle değiştirilmiştir, ancak bu değişiklikler bu durumun sonuçlarını değiştirmez.