2015-04-21 17 views
10

Lütfen dikkat, bu davranışı açıklamanıza yardımcı olun. Aşağıda sunduğum örnek, düşünebildiğim en basit olanıdır, ancak problemi özetlemektedir (C++ 14 ile C++ 14 etkinleştirilmiş g ++ 4.9.2'yi kullanarak). std::mem_fn'a benzer davranacak bir sınıf oluşturmak istiyorum. İşte benim sınıftır.İç yazım hatası, üst sınıflara bağlı olarak değişir

template <class R, class T, R(T::*P)() const > 
struct property { 

    static R get(const T& t) { 
     return (t.*P)(); 
    } 
}; 
R dönüş türüdür

ve T ben ilginç duyuyorum nesne türündendir üçüncü şablon parametresi üye işlevine bir göstericidir. Çok uzak çok iyi.

Daha sonra bu daha önce gösterilen property sınıf kullanılacak sınıftır

class data_class { 

public: 

    unsigned get_data() const { 
     return m_data; 
    } 

private: 
    unsigned m_data; 
}; 

aşağıdaki gibi bir tam sayıyı tutan basit bir sınıfı oluşturur.

Şimdi Onlar aynı iç typedef sahip

struct my_classA 
: public data_class { 

    using data = property<unsigned, data_class, &data_class::get_data>; 
}; 

//same as my_classA, only templated 
template <int I> 
struct my_classB 
: public data_class { 

    using data = property<unsigned, data_class, &data_class::get_data>; 
}; 

şöyle data_class devralan iki sınıfları oluşturmak, ama my_classB şablon olarak değiştirilebilir. Şimdi aşağıdaki türlerde teoride aynı olmalıdır:

using target_t = property<unsigned, data_class, &data_class::get_data>; 
using test1_t = typename my_classA::data; 
using test2_t = typename my_classB<1>::data; 

Ancak benim derleyici yalnızca test1_t ve target_t aynı olduğunu söylüyor. test2_t için çıkarılabilir tip görünüşe

bu tip üye işlevine işaretçisi etrafında bu parantez vardır
property<unsigned int, data_class, (& data_class::get_data)> > 

olduğunu. Neden test2_ttarget_t ile aynı değil? Sisteminizde denemek istediğiniz durumda tam kod. Herhangi bir yardım çok takdir edilir.

#include <type_traits> 

class data_class { 

public: 

    unsigned get_data() const { 
     return m_data; 
    } 

private: 
    unsigned m_data; 
}; 

//takes return type, class type, and a pointer to member function 
//the get function takes an object as argument and uses the above pointer to call the member function 
template <class R, class T, R(T::*P)() const > 
struct property { 

    static R get(const T& t) { 
     return (t.*P)(); 
    } 
}; 

struct my_classA 
: public data_class { 

    using data = property<unsigned, data_class, &data_class::get_data>; 
}; 

//same as my_classA, only templated 
template <int I> 
struct my_classB 
: public data_class { 

    using data = property<unsigned, data_class, &data_class::get_data>; 
}; 

//used to produce informative errors 
template <class T> 
struct what_is; 

//all 3 types below should, in theory, be the same 
//but g++ says that test2_t is different 
using target_t = property<unsigned, data_class, &data_class::get_data>; 
using test1_t = typename my_classA::data; 
using test2_t = typename my_classB<1>::data; 

static_assert(std::is_same<target_t, test1_t>::value, ""); //this passes 
static_assert(std::is_same<target_t, test2_t>::value, ""); //this does not 

int main() { 

    what_is<test1_t> t1; 
    what_is<test2_t> t2; 
} 
+1

Aslında * çok * karışık mesajlar almak için 'test2_t' (bu tür bir değişken bildirme gibi) kullanmaya çalışın:" error: '& data_class :: get_data', "unsigned int" için geçerli bir şablon argümanı değil (data_class: : *)() const '"," hata:' & X :: Y 'biçimindeki bir işaretçi-üye olmalıdır. – hvd

+2

GCC <= 4.8 ve Clang'da çalışır. 4.9+ yılında bir gerileme olarak görünüyor. –

+1

@ T.C: Bunun için teşekkürler. Hata raporuna bağlantı verebilir misiniz lütfen? Ayrıca bir yanıt olarak gönderin, böylece kabul edebilirim :) – linuxfever

cevap

1

C++ 11 ile kodunuzu çalıştırdım çünkü henüz C++ 14'e aşina değilim. Ama tüm değiştirdiğim typedefs ile (takma ad) kullanma ve kodu biraz kolaylaştırdı. Çıktısını etkileyecek bir şey yok.

İstenilen sonuçlara, örneklenen T sınıfı şablonuna T eklendiğinde, R ile T'nin yerini alacak, böylece bu durumda "imzasız" olacak şekilde istenen sonuçları elde ettik.

~$g++ -std=c++11 test.cpp 
~$./a.out 
1 
1 

Sorunun Başlangıçta iki sınıfın sizeof 's yazdırmaya çalıştı çünkü sınıf şablon örneği kriterlerine ilgisi var, my_classA :: veriler:

#include <iostream> 
#include <type_traits> 

template <typename R, typename T, R(T::*P)() const> 
struct property 
{ 
    static R get(const T& t) 
    { 
     return (t.*P)(); 
    } 
}; 


struct data_class 
{ 
    private: 
     unsigned m_data; 

    public: 
     unsigned get_data() const 
     { 
      return m_data; 
     } 
}; 

struct my_classA : public data_class 
{ 
    typedef property<unsigned, data_class, &data_class::get_data> data; 
}; 

template <typename T, int> 
struct my_classB : public data_class 
{ 
    typedef property<T, data_class, &data_class::get_data> data; 
}; 


int main() 
{ 

    typedef typename my_classA::data normClassA; 
    typedef typename my_classB<unsigned,1>::data tmplClassB; 

    std::cout<< std::is_same< property<unsigned, data_class, &data_class::get_data> , normClassA >::value <<std::endl; 
    std::cout<< std::is_same< property<unsigned, data_class, &data_class::get_data> , tmplClassB >::value <<std::endl; 

} 

sonuç şudur 1 döndü, ancak my_classB < 1> :: veri bir derleme hatasıyla bitti. Bunun neden oluştuğuna dair hala bulanıkım. Teknik olarak, sınıf şablonunu gayet iyi örneklendirmeliydi. Belki de yanlış örneklenen classB şablonunun içindeki özelliktir. Buna daha çok bakacağım ama cevabını bulursanız lütfen yayınlayın. Bu ilginç bir şey!

DÜZENLEME: Orijinal kod, Cygwin GCC 4.8.2'de düzgün çalışıyor. Sonuç 1 ve 1'dir. Belki de sadece bir gcc4.9.2 derleyici sorunudur.