2016-07-19 20 views
6

Bir C++ sınıf kitaplığında hata işleme kavramını geçirme görevindeyim. Daha önce basitçe boole (başarı/başarısızlık) döndüren metotlar, bir makine tarafından okunabilir hata kodunu ve insan tarafından okunabilir bir açıklama (ve burada önemi olmayan bir kısmı) taşıyan bir Result nesnesini döndürmek için değiştirilecektir.C++: "Açık" bir görevlendirme operatörü yapabilirim "

Binlerce satırlık kodun yürürlüğe girmesi hataya açık olduğundan, bu görev için derleyiciden en iyi desteği almaya çalışıyorum.

Benim sonuç sınıfı var - diğer üye yöntemler arasında - Bir kod ve kod için bir atama operatöründen sonucunu oluşturur bir yapıcısı:

class Result 
{ 
    public: 
     typedef unsigned long ResultCode; 
     explicit Result(ResultCode code); // (1) 
     Result& operator=(ResultCode code); // (2) 
}; 

Not: Genellikle ResultCode için bir enum sınıfını kullanırsınız hangi Sorunlarımı çözerdi, ama bu bir seçenek değil. Bunun nedeni, ana tasarım nesnesinin farklı kütüphanelerde Result kullanmasıdır, her bir kütüphane için olası tüm sonuç kodlarını tanımlayan bir büyük başlık dosyası gerektirmeden her biri kendi sonuç kümesi kodlarını tanımlamalıdır. Aslında, her sınıf, yerel sonuç kodlarını tanımlayabilecek, böylece olası sonuç kodlarının listesi sınıf başlığından alınabilecektir. Böylece kodlar Result numaralı numarada numaralandırılamaz, bunlar Result sınıfını kullanarak sınıflar tarafından tanımlanmalıdır.

istemci kodunda

return true; 

tablolara ilişkin örtülü dönüşüm önlemek için, yapıcı açık ilan edilmiştir. Ancak yuvalama yöntemi çağrılarında, başka bir sorun oluşur. De ki, ben bir Result nesnesi döndüren bir işlev kullanıyorum bir yöntemini

bool doSomething() 
{ 
    return true; 
} 

var. örtülü dönüştürülür) doSomething boole dönüş değeri (- Ben, bu bana bir derleyici hata vermek etmeyecek iç içe aramalar Result 'ın atama operatörünün geçerli uygulama ile

Result doSomethingElse 
{ 
    Result result = doSomething(); 
    return result; 
} 

sonucu kodlarını iletmek istiyorum imzasız uzun

C++ belgelerinde okuduğum gibi, yalnızca kurucular ve dönüşüm operatörleri açık olarak bildirilebilir.

Sorularım

  1. Neden açık atama operatörleri veya diğer yöntemler için izin verilmez? IMO, herhangi bir yöntemin de açık olmasına izin vermesi çok mantıklı olacaktır.
  2. Atama operatörü için örtülü tür dönüşümü önlemek için başka çözümler var mı?
  3. deftere kodu ile ilgili olarak
+1

Ben istediğiniz cevap değil biliyorum ama neden C++ istisna mekanizması kullanmayın olmak 'yakalama' şey bir unsigned int olmamak üzere şablon overloadng kullanmak ve onu zorlayabilirsiniz? Dili dövmeyin. Onunla çalışın. (Artı güzel sorulan soru için olsa da). – Bathsheba

+2

Şablon void operator = (T) = delete; 'i bildiremediniz ve sahip olduğunuzı saklayın. Normal durumda bunu kullanacak ve diğer tüm tipler için silinen yöntemi kullanmaya çalışacaktır. – doug65536

+0

Mümkün ve hatta teşvik edilip edilmediğini bilmiyorum, ancak bunu kendiniz yapmak yerine [sistem hata sınıflarını] (http://en.cppreference.com/w/cpp/error#System_error) uzatabilirsiniz. ? –

cevap

1

With the current implementation of Result's assignment operator, this is not going to give me a compiler error - the boolean return value of doSomething() is implicitly converted to unsigned long.

; error: no viable conversion from 'bool' to 'Result', see here numaralı hataya neden olur.

Kodda gördüğünüz davranışı gösteren minimal bir örnek gerekli olacaktır. Muhtemelen kod üzerinde materyal etkisi olan gerçek kodda başka bir kurucu veya dönüşüm türü vardır.Açıkça sorulan sorulara On


...

Why is explicit not allowed for assignment operators or other methods?

explicit

sadece örtük dönüştürme gerçekleşebilir nerede izin verilir, yani derleyici özel olduğunu (sizin için dönüşüm sağlama girişiminde nerede bool için durum). Bu tür dönüşümler kurucular ve dönüşüm (veya döküm operatörleri) 'dir.

Kurucu veya dönüştürme işlecini explicit olarak işaretlemek, derleyicinin dönüştürmeyi yapmasını engeller; bu nedenle, dönüşüm gerektiriyorsa, bunun hakkında açık bir şekilde belirtmeniz gerekir - bunun neden yapıldığına dair genel bir motivasyon olarak, kodu yapar ne yaptığını daha açık. Bir trade-off var, bu yüzden her iki durumda da mantıklı kullanım uygulanmalıdır. Genel tavsiye, şüphe edildiğinde explicit'u desteklemektir.

Örneğin;

struct Result { 
    Result(long src); // can be marked explicit 
    operator long() const; // can be marked explicit 
}; 

Are there other solutions to prevent implicit type conversion for the assignment operator?

atama operatörü Result& operator=(Result&); için özel bir yer alır. Ödevin kendisinde herhangi bir dönüşüm yoktur. Ödev için bir Result örtük oluşturulmasını önlemek için, kurucu (lar) explicit olarak işaretlenmelidir.

Result'un ResultCode'dan oluşturulmasını önlemek için, yöntemi bildiremez veya silinmiş olarak işaretleyebilirsiniz;

Result& operator=(ResultCode code) = delete; 
+0

Dönüştürme değilse, Sonuç Sonucu sonuçlarının arkasında neler olur = true; o zaman bu bana 1 –

+0

Sonuç kodu ile cevap veriyor Ne derleyici kullanıyorsunuz? Bu bana gcc, clang ve msvc'de bir hata veriyor. – Niall

+0

@kritzel_sw. Derlemeyi (beklediğiniz gibi değil) gösteren minimal bir örnek var mı? – Niall

2

Senin sorunun sınıfında Result değil: Eğer açıkça sonuçta bunun yeni bir örneğini oluşturarak vardır; explicit bunu yasaklayamaz.

Sana örtülü promosyon bool -> long korusun sanmıyorum.

Etrafında çalışabilirsiniz. Bir yol ResultCode'u bir tamsayı türü yapmaktır. daha sonra açık bir kurucuya sahip olabilir. Bir olmadığı bir ResultCode (örneğin Result yapıcı olarak!) bir şey ile

class ResultCode 
{ 
unsigned long m_code; 
public: 
explicit ResultCode(unsigned long code) : m_code(code) {} 
operator unsigned long() { return m_code; } 
}; 

gibi bir şey aramak bekliyor bir işlevi her yerde bir unsigned int kullanabilirsiniz ResultCode kullanabilir ve ResultCode res = 5 veya return ResultCode(5) olarak oluşturmanız ancak izin verecek zaten, ReturnCode işlevini döndürmesi gerekiyorsa return 5 gibi bir şey yapmayın.

Aksi takdirde bir hata

typedef unsigned long ResultCode; 

class Result 
{ 
    ResultCode m_par; 

public: 
    template<typename T> 
    Result(T param) { static_assert(false); } 

    template<> 
    Result(ResultCode par): m_par(par) {} 
}; 

int main() 
{ 
    ResultCode a = 5;  //ok 
    //unsigned long a = 6; //also ok 
    //bool a = true;  //error! 
    //int a = 7;   //also error!! 
    Result b(a); 
}