2014-04-21 24 views
8

Bir işlevin hem beklenen tür hem de bu tür yazım denetimi olan herhangi bir türü kabul ettiği aşağıdaki programa dikkat edin.İlkel olmayan türleri nasıl yazarım?

//a user defined type 
class Widget{}; 

//a function that takes a Widget 
void function (Widget w){} 

int main(){ 

    //make a typedef (this is C++11 syntax for a typedef. It's the same thing) 
    using Gadget = Widget; 

    //make the two "different types" (well.. they're not really different as you will see) 
    Widget w; 
    Gadget g; 

    //call a function that should ONLY accept Widgets 
    function(w); //works (good) 
    function(g); //<- works (I do not want this to compile though) 

} 

Gördüğünüz gibi, bir yazım hatası aslında yeni bir türü ayırt etmiyor. Ben türünden devralan yerine düşündü:

//inherit instead 
class Gadget: public Widget{}; 

//make the two "different types" 
Widget w; 
Gadget g; 

//call the function that should ONLY accept widgets 
function(w); //works (good) 
function(g); //<- works (I do not want this to compile though) 

Aynı sorun.

#include <boost/serialization/strong_typedef.hpp> 

//a user defined type 
class Widget{}; 

//a function that takes the user defined type 
void function (Widget w){} 

int main(){ 

    //try to strongly typedef 
    BOOST_STRONG_TYPEDEF(Widget, Gadget) 

    //make the two "different types" 
    Widget w; 
    Gadget g; 

    //call the function that should ONLY accept widgets 
    function(w); 
    function(g); 

} 

hataları derleme:

In member function ‘bool main()::Gadget::operator==(const main()::Gadget&) const’: 
error: no match for ‘operator==’ (operand types are ‘const Widget’ and ‘const Widget’) 
    BOOST_STRONG_TYPEDEF(Widget, Gadget) 
^
In member function ‘bool main()::Gadget::operator<(const main()::Gadget&) const’: 
error: no match for ‘operator<’ (operand types are ‘const Widget’ and ‘const Widget’) 
    BOOST_STRONG_TYPEDEF(Widget, Gadget) 
^

Görünüşe BOOST_STRONG_TYPEDEF sadece ilkel türleri ile çalışan boost baktığımızda
, Ben güçlü typedef denemek düşündük.

//I want the functionality, but these are NOT the same type! 
class Gadget: public Widget{ 
    operator Widget() = delete; 
}; 

da işe yaramadı:
tekrar devralma, ama örtük dönüştürme durdurmaya çalıştı.

Sorular:

  1. Neden strong_typedef sadece ilkel türleri üzerinde çalışmak artırmak geliyor?
  2. Güçlendirmek için benzer bir işlev almak için ilkel olmayan bir türü nasıl yazabilirim? Bazı özel miras ve bazı using s kullanıyor olabilirsiniz?
+1

Sanırım WidgetBase sınıfını kullanacağım ve sınıf Widget'ını yapacağım: public WidgetBase; sınıf Gadget: genel WidgetBase'. – xis

+0

@zneak: Bu, BOOST_STRONG_TYPEDEF'in yaptığı şeydir. – Deduplicator

+0

@Deduplicator Uygulamaya bakıldığında strong_typedef bir miras değil, bir üyeyi kullanıyor. – pmr

cevap

1

class Gadget : Widget { using Widget::Widget; using Widget::foo; ... }; 
+0

Bence bu, listelemek için çok fazla yöntem veya veri üyesi olmadığını varsayan bir çözüm. –

5

Temel olarak, aynı davranışı olan birbiriyle ilgisiz iki sınıfa ihtiyacınız vardır. Bunun için bir parametrized şablon kullanmak olacaktır:

template<int tag> class WidgetGadget { ... }; 
typedef WidgetGadget<0> Widget; 
typedef WidgetGadget<1> Gadget; 
3

BOOST_STRONG_TYPEDEF aslında tipleri, (==) equatable atanabilir (=) ve daha az-daha-karşılaştırılabilir (<) varsayar.

Yazımınız yoksa, makro, şahit olduğunuz gibi derleme yapmayan bir kodla sonuçlanır. Kendi makronuzu kullanabilir veya gerekli işlemler için uygulamalar sağlayabilirsiniz.

Sen februari 2012 yılından itibaren bu yanıtında bir CUSTOM_STRONG_TYPEDEF bulabilirsiniz: How to use comparison operators on variant with contained types?, açıkça kullanım örneği için daha açık yapılmış örnek varsayılan karşılaştırma davranışı

Güncelleme alma kaçınır, Live On Coliru görmek

//a user defined type 
class Widget{}; 
class Frobnicator{}; 

///////////////////////////////////////////////////// 
// copied and reduced from boost/strong_typedef.hpp 
#define CUSTOM_STRONG_TYPEDEF(T, D)         \ 
struct D               \ 
    /*: boost::totally_ordered1< D   */      \ 
    /*, boost::totally_ordered2< D, T  */      \ 
    /*> >         */      \ 
{                 \ 
    T t;               \ 
    explicit D(const T t_) : t(t_) {};        \ 
    D(){};               \ 
    D(const D & t_) : t(t_.t){}          \ 
    D & operator=(const D & rhs) { t = rhs.t; return *this;}  \ 
    D & operator=(const T & rhs) { t = rhs; return *this;}   \ 
    explicit operator const T &() const {return t; }    \ 
    explicit operator T &() { return t; }       \ 
    /*bool operator==(const D & rhs) const { return t == rhs.t; } */\ 
    /*bool operator<(const D & rhs) const { return t < rhs.t; } */\ 
}; 

CUSTOM_STRONG_TYPEDEF(Widget, Gadget) 
CUSTOM_STRONG_TYPEDEF(Frobnicator, Normalcy) 

void acceptWidget(Widget){} 
void acceptGadget(Gadget){} 
void acceptFrobnicator(Frobnicator){} 
void acceptNormalcy(Normalcy){} 

int main(){ 

    //make the two "different types" (well.. they're not really different as you will see) 
    Widget w; 
    Gadget g; 

    //call a function that should ONLY accept Widgets 
    acceptWidget(w); //works (good) 
    acceptGadget(g); 

    //acceptWidget(g); // Error 
    //acceptGadget(w); // Error 
    // but we can enjoy conversions if we summon them 
    acceptWidget(static_cast<Widget&>(g)); 

    Frobnicator f; 
    Normalcy n; 
    acceptFrobnicator(f); 
    acceptNormalcy(n); 

} 
+0

Orijinal soruda verilen problemi çözmek için, operatör T için son iki yöntemin yorumlanması gerekir. Bu iyi bir çözümdür, ancak farklı türlerle başa çıkmak için tekrar tekrar yazılması gerekir. Böylece makrolar benzersiz bir şekilde adlandırılmalıdır. –

+0

Ne demek istediğini anlamıyorum. Esasen sadece diğer cevabı alıntıladım. Ancak, 'açık' dönüşümlerini yapacak, ve, bunu tekrar tekrar yazmak zorunda değilsiniz? Cevabımı güncelledi. Bakın [Coliru'da Canlı] (http://coliru.stacked-crooked.com/a/458fdbd342cb09e6) ** – sehe

+0

Ah! Şimdi açıkları görüyorum. Bu makronun yalnızca bir tür sınıf işlevi için nasıl kullanılabileceğini göstermek için örnek programınıza ekledim. Böylece, bu farklı durumları ele almak için birden çok makro yazmam gerekecekti. http://coliru.stacked-crooked.com/a/8d80373ebd596c61 –