Typedef ne zaman kullanılır?


14

C ++ 'da typedef kullanması gerekip gerekmediği konusunda biraz kafam karıştı. Okunabilirlik ve netlik arasında dengeleyici bir hareket olduğunu hissediyorum.

İşte herhangi bir typedefs olmadan bir kod örneği:

int sum(std::vector<int>::const_iterator first, 
        std::vector<int>::const_iterator last)
{
    static std::map<std::tuple<std::vector<int>::const_iterator,
                               std::vector<int>::const_iterator>,
                    int> lookup_table;

    std::map<std::tuple<std::vector<int>::const_iterator,
                        std::vector<int>::const_iterator>, int>::iterator lookup_it =
        lookup_table.find(lookup_key);

    if (lookup_it != lookup_table.end())
        return lookup_it->second;            

    ...
}

Oldukça çirkin IMO. Bu yüzden, daha güzel görünmesi için işlev içine bazı typedefs ekleyeceğim:

int sum(std::vector<int>::const_iterator first, 
        std::vector<int>::const_iterator last)
{
    typedef std::tuple<std::vector<int>::const_iterator,
                       std::vector<int>::const_iterator> Lookup_key;
    typedef std::map<Lookup_key, int> Lookup_table;

    static Lookup_table lookup_table;

    Lookup_table::iterator lookup_it = lookup_table.find(lookup_key);

    if (lookup_it != lookup_table.end())
        return lookup_it->second;            

    ...
}

Kod hala biraz sakar, ama çoğu kabus malzemesinden kurtuluyorum. Ancak hala int vektör yineleyicileri var, bu varyant bunlardan kurtuluyor:

typedef std::vector<int>::const_iterator Input_iterator;

int sum(Input_iterator first, Input_iterator last)
{
    typedef std::tuple<Input_iterator, Input_iterator> Lookup_key;
    typedef std::map<Lookup_key, int> Lookup_table;

    static Lookup_table lookup_table;

    Lookup_table::iterator lookup_it = lookup_table.find(lookup_key);

    if (lookup_it != lookup_table.end())
        return lookup_it->second;            

    ...
}

Bu temiz görünüyor, ama yine de okunabilir mi?

Ne zaman bir typedef kullanmalıyım? Kabus tipim olur olmaz? Bir kereden fazla meydana gelir gelmez? Onları nereye koymalıyım? Bunları işlev imzalarında kullanmalı mıyım yoksa uygulamaya koymalı mıyım?


1
Yinelenen değil, ama biraz soru ile ilgili programmers.stackexchange.com/questions/130679/…
c0da

typedef Input_iterator std::vector<int>::const_iterator;geriye
Per Johansson

1
Okunabilirlik ve netlik arasında bir fark var mı?
Neil

Ne zaman #defineaint yeterince iyi.
Thomas Eding

Yanıtlar:


6

Son örneğiniz çok okunabilir, ancak typedef'i tanımladığınız yere bağlıdır. Yerel kapsam tip tanımları (ikinci örneğiniz gibi) IMVHO neredeyse her zaman bir kazançtır.

Yine de üçüncü örneğinizi en çok beğeniyorum, ancak adlandırma hakkında düşünmek ve kabın amacını anlatan yineleyicilere ad vermek isteyebilirsiniz.

Başka bir seçenek de, farklı kaplarla da çalışabilmesi için işlevinizden bir şablon oluşturmak olacaktır. Çizgileri boyunca

template <typename Input_iterator> ... sum(Input_iterator first, Input_iterator last) 

bu da STL'nin ruhunda çok fazla.


2

A'yı typedefbir işlevin değişken bildirim eşdeğeri olarak düşünün : işte orada ...

  • ... aynı türü (ilk iki örneğinizin yaptığı gibi) tekrar kullanırken kendinizi tekrar etmek zorunda değilsiniz.
  • ... türün kanlı ayrıntılarını gizleyebilir, böylece her zaman ekranda görünmezler.
  • ... türdeki değişikliklerin kullanıldıkları her yere yansıtıldığından emin olun.

Şahsen, uzun süreli isimleri std::vector<int>::const_iteratortekrar tekrar okumak zorunda kalırsam sırlıyorum.

Üçüncü örneğiniz gereksiz yere tekrarlanmaz ve okunması en kolay yoldur.


1

typedefbeyanlar temel olarak kapsülleme ile aynı amaca hizmet eder. Bu nedenle, sınıflarınızla aynı adlandırma kurallarını izleyerek neredeyse her zaman bir başlık dosyasına en iyi şekilde uyarlar, çünkü:

  • Eğer ihtiyacınız varsa typedef, özellikle argümanlarda kullanıldığı örnekte olduğu gibi arayanlar da olacaktır.
  • Türü kendi sınıfınızla değiştirmek de dahil olmak üzere herhangi bir nedenle değiştirmeniz gerekiyorsa, bunu yalnızca tek bir yerde yapmanız gerekir.
  • Karmaşık türlerin tekrar tekrar yazılması nedeniyle hatalara daha az eğilimli olmanızı sağlar.
  • Gereksiz uygulama ayrıntılarını gizler.

Bir kenara, daha fazla soyutlarsanız, not kodunuz çok daha temiz olurdu, örneğin:

if (lookup_table.exists(first, last))
    return lookup_table.get(first, last);

Öneriniz daha temiz görünebilir, ancak aramayı iki kez yaparak zaman harcar.
Derek Ledbetter

Evet, bu kasıtlı bir takastı. Özellikle iplik güvenliği konusunda endişe duymuyorsanız, neredeyse temiz olan tek bir arama ile bunu yapmanın yolları vardır.
Karl Bielefeldt
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.