(Nasıl) bir numaralandırmadaki öğeleri sayabilirim?


98

Böyle bir şey varken bu soru aklıma geldi

enum Folders {FA, FB, FC};

ve her klasör için bir dizi kapsayıcı oluşturmak istedi:

ContainerClass*m_containers[3];
....
m_containers[FA] = ...; // etc.

(Kullanılması kullanımda çok daha zarif eşler: std::map<Folders, ContainerClass*> m_containers;)

Ancak asıl soruma geri dönersek: Dizi boyutunu sabit kodlamak istemiyorsam, Klasörler'de kaç öğe olduğunu bulmanın bir yolu var mı? (Örneğin FC, ContainerClass*m_containers[FC+1]yanılmıyorsam gibi bir şeye izin verecek listedeki son öğe olmaya güvenmeden .)



1
Soru biraz belirsiz. C ++ standardına göre, int(FA) | int(FB) | int (FC)bir Foldersdeğişken için de yasal bir değerdir . Herhangi m_containersbir Foldersdeğişkeni geçerli bir dizin [FC+1]olacak şekilde boyutlandırıyorsanız , yeterince büyük olmaz.
MSalters


Yanıtlar:


123

Bunu yapmanın gerçekten iyi bir yolu yoktur, genellikle numaralandırmada fazladan bir öğe görürsünüz, yani

enum foobar {foo, bar, baz, quz, FOOBAR_NR_ITEMS};

Böylece şunları yapabilirsiniz:

int fuz[FOOBAR_NR_ITEMS];

Yine de pek hoş değil.

Ancak elbette bir numaralandırmadaki öğe sayısının güvenli olmadığının farkındasınız, örneğin

enum foobar {foo, bar = 5, baz, quz = 20};

öğe sayısı 4 olacaktır, ancak enum değerlerinin tamsayı değerleri dizi dizini aralığının dışında olacaktır. Dizi indeksleme için enum değerleri kullanmak güvenli değildir, diğer seçenekleri göz önünde bulundurmalısınız.

düzenleme: istendiği gibi, özel girişin daha fazla öne çıkmasını sağladı.


27
Onu SON veya HER ZAMAN_AT_END veya çok şifreli olmayan bir şey olarak adlandırın. O Make dışarı sopa . Böylece sonraki bakımcılar siz işaretleyiciyi bitirdikten sonra yanlışlıkla yeni girişler eklemeyin.
Martin York

3
İyi ya da kötü, organizasyonumuzda benimsediğimiz yaklaşım budur. Normalde buna FINAL_enumname_ENTRY diyoruz, örneğin FINAL_foobar_ENTRY. Ayrıca, insanların numaralandırma bildiriminden hemen sonra tanımlanan ayrı bir statik sabit FOOBAR_COUNT değişkeni kullandıklarını da gördüm, bu biraz daha fazla hataya açık bir yaklaşımdır.
Darryl

1
En azından "enum foo {a = 10, LAST}" ifadesinin tuhaf olacağını görmek oldukça kolay. Ve ben "int arr [SON]" un bu durumda 2 değil 11 öğe olacağını düşündüm, bu yüzden çoğu kod işe yarayacak (ancak geçersiz indeks değerlerinde hafızayı boşa harcıyorsunuz)
Code Abominator

32

C ++ için, çeşitli tür güvenli numaralandırma teknikleri mevcuttur ve bunlardan bazıları (önerilen ancak hiçbir zaman sunulmayan Boost.Enum gibi ) bir numaralandırmanın boyutunu almak için destek içerir.

C ve C ++ 'da çalışan en basit yaklaşım, numaralandırma türlerinizin her biri için bir ... MAX değeri bildirme kuralını benimsemektir:

enum Folders { FA, FB, FC, Folders_MAX = FC };
ContainerClass *m_containers[Folders_MAX + 1];
....
m_containers[FA] = ...; // etc.

Düzenleme : { FA, FB, FC, Folders_MAX = FC}Versus ile ilgili olarak {FA, FB, FC, Folders_MAX]: ... MAX değerini birkaç nedenden ötürü numaralamanın son yasal değerine ayarlamayı tercih ederim:

  1. Sabitin adı teknik olarak daha doğrudur (çünkü Folders_MAXmümkün olan maksimum enum değerini verir).
  2. Şahsen, Folders_MAX = FCdiğer girişlerden biraz daha fazla öne çıkmış gibi hissediyorum (maksimum değeri güncellemeden yanlışlıkla enum değerleri eklemeyi biraz zorlaştırıyor, Martin York'un başvurduğu bir sorun).
  3. GCC, aşağıdaki gibi kod için "anahtara dahil olmayan numaralandırma değeri" gibi yararlı uyarılar içerir. Folders_MAX == FC + 1'e izin vermek, anahtara asla dahil edilmemesi gereken bir sürü ... MAX numaralandırma değerine sahip olduğunuz için bu uyarıları bozar.
anahtarı (klasör) 
{
  durum FA: ...;
  FB vakası: ...;
  // Oops, FC'yi unuttum!
}

3
Neden yapmıyorsun: enum Folders { FA, FB, FC, Folders_MAX }; ContainerClass *m_containers[Folders_MAX];?
Bill

1
Sonuncunun bir sayı olduğunu açıkça belirtmeyi tercih ederim ve hepsi aynı ada sahip:struct SomeEnum { enum type {FA, FB, FC, NB__};};
Luc Hermitte

2
Aslında bu "yardımcı" uyarıların tam bir baş ağrısı olduğunu hissediyorum. İyi uyarıları severim, geliştirirken her zaman -Wall -pedantic vb. Ayarlarım, ancak bu uyarılar sadece aptalca. Daha kötüsü, && için önerme parantezleri gibi || ve & ^ | Operatör Önceliği. Ben java cehennem C ve C ++ başına gelenleri çocuk bakıcısı dili, ... olduğunu sanıyordum
wich

2
Folders_max = FC'ye sahip olmanın dezavantajı, sıralamaya her bir şey eklediğinizde onu değiştirmeniz gerektiğidir!
Étienne

2
enum Klasörler {FA, FB, FC, Folders_MIN = FA, Folders_MAX = FC}; Sadece yineleme için yararlı olduğunu vurgulamak için mi?
gjpc

7

STL tarzında özellikler hakkında ne düşünüyorsunuz? Örneğin:

enum Foo
{
    Bar,
    Baz
};

yaz

std::numeric_limits<enum Foo>::max()

uzmanlaşma (c ++ 11 kullanıyorsanız muhtemelen constexpr). Ardından, test kodunuzda std :: numeric_limits :: max () = last_item gibi kısıtlamaları korumak için statik iddiaları sağlayın.


2
Maalesef bu, bu cevaba göre işe yaramayacak .
rr-

3
std::numeric_limits<enum Foo>::max()her zaman sıfır döndürür ... (bağlantılı yanıt için soruya bakın) Normal numaralandırmalar ( enum Foo { ... }) üzerinde, tür ipuçlu numaralandırmalar ( enum class Foo : uint8_t { ... }) gcc 5.2.0 @ Linux ve MinGW 4.9.3 @ Windows ile test edilmiştir .
rr-

1
(... ve olması durumunda std::numeric_limits<std::underlying_type<Foo>::type>::max(), temeldeki türün maksimum değerini döndürür, yani bu bağlamda kullanışlı olmayan 32 bitlik tamsayılar için 0xFFFFFFFF.)
rr-

1
Garip, çünkü anlattıklarımı yapan bir çalışma kodum var. namespace gx { enum struct DnaNucleobase : char { A, C, G, T }; } Sonra: namespace std { template<> struct numeric_limits<enum ::gx::DnaNucleobase> { typedef enum ::gx::DnaNucleobase value_type; static constexpr value_type max() { return value_type::T; } (...) Ve std::cout << std::numeric_limits<::gx::DnaNucleobase>::max() << std::endl;beklenen sonucu yazdırır. Gcc 5.2.1 ve 4.8 / 4.9 aromaları ile test edilmiştir.
Wojciech Migda

2
-1; Cevabı değiştirirseniz bana ping atın, böylece olumsuz oyu geri alabilirim. Bu cevap, uyulması gereken kötü bir kuraldır. Kavramının kötüye kullanılmasıdır numeric_limits<T>::max(). Fonksiyonun makul bir şekilde döndürebileceği tek şey, numaralandırılmış en yüksek değerdir. Geri dönecekti 2, ancak OP'nin (bu özel durumda) geri dönmesi gerekecekti 3. Enum ( FB = 2057) için varsayılan olmayan değerlere sahip olduğunuzda , tüm bahisler kapalıdır, hatta bir + 1defaya mahsus hatayı kesemezsiniz. Bir numeric_limits<T>::number_of_elements_of_the_set()(veya daha kısa bir ad) olsaydı , bu belirsizlik olmadan kullanılabilirdi.
Merlyn Morgan-Graham

3

Numaranızın sonuna Folders_MAX veya benzer bir adla bir girdi ekleyin ve dizilerinizi başlatırken bu değeri kullanın.

ContainerClass* m_containers[Folders_MAX];

2

Numaralandırmaları işlevlerim için bağımsız değişken olarak kullanmayı seviyorum. Sabit bir "seçenekler" listesi sunmanın kolay bir yoludur. Buradaki en çok oylanan cevapla ilgili sorun, bunu kullanarak bir müşterinin "geçersiz bir seçenek" belirleyebilmesidir. Döndürme olarak, esasen aynı şeyi yapmanızı öneririm, ancak bunların sayısını tanımlamak için numaralamanın dışında sabit bir int kullanın.

enum foobar { foo, bar, baz, quz };
const int FOOBAR_NR_ITEMS=4;

Hoş değil, ancak sabiti güncellemeden numaralandırmayı değiştirmezseniz temiz bir çözümdür.


1

C ++ 'da bir numaralandırmadaki değerlerin sayısına gerçekten ulaşmanın bir yolunu gerçekten görmüyorum. Daha önce bahsedilen çözümlerden herhangi biri, çok büyük veya çok küçük diziler oluşturduğunuz durumlarla karşılaşabileceğiniz değerinizi tanımlarsanız, numaralandırmalarınızın değerini tanımlamadığınız sürece çalışır.

enum example{ test1 = -2, test2 = -1, test3 = 0, test4 = 1, test5 = 2 }

Bu örneklerle ilgili olarak, sonuç, 5 öğelik bir diziye ihtiyacınız olduğunda 3 öğelik bir dizi oluşturacaktır.

enum example2{ test1 , test2 , test3 , test4 , test5 = 301 }

bu hakkındaki örneklerde, sonuç, 5 öğelik bir diziye ihtiyacınız olduğunda 301 öğelik bir dizi oluşturacaktır.

Genel durumda bu sorunu çözmenin en iyi yolu, numaralandırmalarınızı yinelemek olacaktır, ancak bu, bildiğim kadarıyla henüz standartta değildir.

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.