2015-05-27 31 views
7

Çeşitli farklı türlerdeki verileri depolamak için bir birleşim kullanan özel bir varyant türü uygulamaya çalışıyorum. type_id alanında, birleşikte kayıtlı olan veriyi depolamayı planlıyorum. Birlik önemsiz üyeler içerir. Çağrı MyVariant arasında örtük silinmiş varsayılan yapıcı için: şu hata mesajını alıyorumÖnemsiz üyelerle birliği içeren kurucu için oluşturucu ve kopya yapıcı

MyVariant v; 

:

struct MyVariant { 
    enum { t_invalid, t_string, t_int, t_double, t_ptr, t_dictionary } type_id; 
    union { 
    int        as_int; 
    double       as_double; 
    std::string      as_string; 
    std::unique_ptr<int>   as_ptr; 
    std::map<int, double>   as_dictionary; 
    }; 
}; 

Ben MyVariant gibi bir örneğini oluşturmaya çalışırken aşağıdaki gibidir: İşte benim şimdiki uygulamasıdır. Yani, el yapıcı uygulamak gibi çalıştı aşağıdaki gibidir: silinen bir işlevi kullanmak Girişimi: Bana benzer hata mesajı verir

MyVariant() : type_id{t_int}, as_int{0} {} 

.

MyVariant(int value) : type_id{t_int}, as_int{value} {} 

ve aşağıdaki gibi benim örneğini oluşturmak: Sonra, ben aşağıdaki kurucu uygulamaya çalışmıştır

MyVariant v{123}; 

=> aynı hata iletisi: silinen bir işlevi kullanmak çalışıldı.

Ayrıca bir kopya oluşturucu uygulamaya başladım, aşağıdaki gibi görünüyor. Ancak, elbette bu derleyici hataları ile yardımcı olmaz.

MyVariant::MyVariant(const MyVariant& other) 
{ 
    type_id = other.type_id; 
    switch (type_id) { 
     case t_invalid: 
      break; 
     case t_string: 
      new (&as_string) std::string(); 
      as_string = other.as_string; 
      break; 
     case t_int: 
      as_int = other.as_int; 
      break; 
     case t_double: 
      as_double = other.as_double; 
      break; 
     case t_ptr: 
      new (&as_ptr) std::unique_ptr<int>(nullptr); 
      as_ptr = std::make_unique<int>(*other.as_ptr); 
      break; 
     case t_dictionary: 
      new (&as_dictionary) std::map<int, double>(); 
      // TODO: copy values from other 
      break; 
    } 
} 

Xcode ve Apple LLVM 6.1'i derleyici olarak kullanıyorum.

Ana soru şu: Neden aldığım derleyici hatalarını alıyorum ve derlemeyi yapmak için kodumu nasıl değiştirmem gerekiyor?

Ek soru şudur: Yapımcı ve kopya oluşturucu için uygulamam ile doğru yolda mıyım?

+0

Bu varsayılan kurucu tamam. Bir yıkıcıyı uygulaman gerekiyor. –

+0

Bir örneğinizin tahsis edildiği parens yerine parantez kullanmak mı istiyorsunuz? – donjuedo

+0

@donjuedo Evet, diş tellerini kullanmak istedim çünkü üniform C++ 11 başlatma sözdizimine sadık kalmak istiyorum. Onlarda yanlış bir şey var mı? – j00hi

cevap

7

Sendikanız tipi önemsiz olmayan varsayılan/kopyala/taşı kurucular, kopyalama/taşıma atama operatörleri ve yıkıcı, her biri string, unique_ptr ve map, veri üyesi vardır. Bu nedenle, bunların hepsi sendikanız için gizli olarak silinmiştir.

§9.5/2 [class.union]

... [Not: Bir birliğin herhangi statik olmayan veri üyesi önemsiz olmayan bir varsayılan kurucu varsa (12.1) , kopya kurucu (12.8), kurucu (12.8), kopya atama operatörü (12.8), hareket atama operatörü (12.8) veya yıkıcı (12.4), birleştirme üyesinin ilgili üye işlevinin kullanıcı tarafından sağlanmalı veya sendika için örtülü olarak silindi (8.4.3). -end not]

Yani el birliği için bu uygulamalıdır. En azından, MyVariant örneğini oluşturabilmeniz için sınıfın yapılandırılabilir ve yıkılabilir olması gerekir.Yani

MyVariant() : type_id{t_int}, as_int{0} {} 
~MyVariant() 
{ 
    switch(type_id) 
    { 
     case t_int: 
     case t_double: 
     // trivially destructible, no need to do anything 
     break; 
     case t_string: 
     as_string.~basic_string(); 
     break; 
     case t_ptr: 
     as_ptr.~unique_ptr(); 
     break; 
     case t_dictionary: 
     as_dictionary.~map(); 
     break; 
     case t_invalid: 
     // do nothing 
     break; 
     default: 
     throw std::runtime_error("unknown type"); 
    } 
} 

Kopyanız yapıcı uygulaması geçerli görünüyor gerek ama ne ben farklı yapardım ilk varsayılan sadece yerleşiminde inşa kopyalama elemanı inşa ve ardından kaynak nesneden kopyalamak yerine yeni kendini çağırır . unique_ptr üye etkindir ve bir temel sınıf işaretçi üzerinden bazı türetilmiş sınıf örneğine bir işaretçi depolamak edilirse, o zaman kopya yapıcı uygulaması sadece taban sınıfı kısmını kopyalar olduğunu

MyVariant(const MyVariant& other) 
{ 
    type_id = other.type_id; 
    switch (type_id) { 
     case t_invalid: 
      break; 
     case t_string: 
      new (&as_string) auto(other.as_string); 
      break; 
     case t_int: 
      as_int = other.as_int; 
      break; 
     case t_double: 
      as_double = other.as_double; 
      break; 
     case t_ptr: 
      new (&as_ptr) auto(std::make_unique<int>(*other.as_ptr)); 
      break; 
     case t_dictionary: 
      new (&as_dictionary) auto(other.as_dictionary); 
      break; 
    } 

Live demo

Not. Son olarak, bunu bir öğrenme alıştırması olarak yapmazsanız, kendi yuvarlamak yerine Boost.Variant'u kullanmanızı şiddetle tavsiye ederim.

+3

Tidbit: 'new (& as_dictionary) auto (other.as_dictionary)' ve daha fazlası, artıklığın bir kısmından kurtulabilir ve daha fazla arkadaşça refactoring yapar. –

+0

Boost.Variant, şu anki C++ durumu için oldukça modası geçmiş. – Orient

+0

@Orient Neden düşünüyorsunuz, Boost.Varant güncel değil mi? Ve buna iyi, modern bir alternatif ne olurdu? – j00hi