2010-12-11 17 views
15

bazen böyle bir kod yazmak:CRTP kullanırken hatalar nasıl önlenir? <a href="http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern">CRTP</a> kullanma

// this was written first 
struct Foo : Base<Foo, ...> 
{ 
    ... 
}; 

// this was copy-pasted from Foo some days later 
struct Bar : Base<Foo, ...> 
{ 
    ... 
}; 

Ve ayıklayıcısında kod iz ve Bar'ın üyeleri Base kullanılan olmadığını görene kadar, yanlış giderse anlamak çok zordur.

Bu hatayı derleme zamanında nasıl gösteririz?

(ı MSVC2010 kullanmak, bu yüzden biraz C++ 0x özellikleri ve MSVC dil uzantıları kullanabilirsiniz)

cevap

12

C++ 0x'de basit bir çözümünüz var. Ancak MSVC10'da uygulanıp uygulanmadığını bilmiyorum.

template <typename T> 
struct base 
{ 
private: 
    ~base() {} 
    friend T; 
}; 

// Doesn't compile (base class destructor is private) 
struct foo : base<bar> { ... }; 
+0

aslında dtor hiç çağrılmadıysa çalışmaz. – Abyx

+0

@Abyx: İlginç bir şekilde gcc 4.9 ile, eğer struct struct türünde bir nesne oluşturmak için yeni yerleşim kullanırsam: base {} ', * constructor *' S :: S() 'dan dolaylı olarak silindiğinden şikayetçi olur. özel olarak. Ancak bu durumda yıkıcı asla çağrılmaz. –

+0

Daha ilginç olarak, gcc 4.8.1 hiç şikayet etmiyor! –

0

türetilmesi türünü bilmenin bir yolu yoktur. Base<Foo>'dan türetilen Foo'u uygulayabilirsiniz, ancak başka sınıfların da bundan kaynaklanmadığını söyleyemezsiniz.

0

Ben makro

#define SOMENAMESPACE_BASE(type, arg1, arg2) type : Base<type, arg1, arg2> 

kullanabilirsiniz ama daha iyi bir çözüm varsa makroları kullanmak istemiyoruz. değil türetilmiş sınıfın adını içeren do

template<class T> class Base { 
protected: 
    // derived classes must call this constructor 
    Base(T *self) { } 
}; 

class Foo : public Base<Foo> { 
public: 
    // OK: Foo derives from Base<Foo> 
    Foo() : Base<Foo>(this) { } 
}; 

class Moo : public Base<Foo> { 
public: 
    // error: constructor doesn't accept Moo* 
    Moo() : Base<Foo>(this) { } 
}; 

class Bar : public Base<Foo> { 
public: 
    // error: type 'Base<Bar>' is not a direct base of 'Bar' 
    Bar() : Base<Bar>(this) { } 
}; 
10

Böyle bir şey kullanabilirsiniz.

+0

Foo'nun kendisi bir şablon olduğunda gerçekten çok ayrıntılı hale gelir. –

+3

@Alexandre: şablonlar ayrıntılıdır. – Amnon

+0

evet öyle, ancak üretim kodunda, kodunuzun düz CRTP'den daha zorlaşması (bu satırlar boyunca OP ile aynı nedenden ötürü bir kez kullanmaya çalıştım). –

2
template<typename T, int arg1, int arg2> 
struct Base 
{ 
    typedef T derived_t; 
}; 

struct Foo : Base<Foo, 1, 2> 
{ 
    void check_base() { Base::derived_t(*this); } // OK 
}; 

struct Bar : Base<Foo, 1, 2> 
{ 
    void check_base() { Base::derived_t(*this); } // error 
}; 

Bu kod Amnon's answer dayalı ancak kod kontrol ediyor, bu yüzden kopyalayıp değişiklik olmadan yapıştırabilirsiniz:

İlgili konular