2015-03-09 19 views
6

Şablondan belirlenen bir değerler dizisi verilen değişken boyutta bir renk sınıfı oluşturmaya çalışıyorum, dizideki her değerin adlandırılmış takma adlarını oluşturmak istiyorum yani:C++ (Her nasılsa) yapısını ana birim boyutuna sınırla

template<int C = 3, typename T = unsigned char> 
class Color { 
public: 
    union { 
    T v[C]; 
    struct { 
     T r, g, b, a; 
    }; 
    }; 
}; 

Ancak, C = 3 için aynı sınıf kullanmak deneyin, birlik görev 4 baytlık bir boyutu ('a' üyesi). Alternatif olarak, bir (a, anonim T üyesi olarak adlandırılan yapı, boyut C> 3'te 1 olarak değerlendirilir) için bir matematiksel olarak ifade edilen bitfield boyutu kullanılarak, derleyici, daha büyük bir uygun olmayan bir izin veren (In gcc, how to mute the -fpermissive warning? uyarınca, baskılamayan bir uyarı) yayınlar. ölçekli API.

Tek bir sınıfa değişken sayılar işlemeye devam ederken, değişken değişken adlarını koruyarak ve özyinelemeli makro sihri uygulamadan (bunu denemeliydim), nasıl kullanmalıyım? Şimdiden teşekkürler!

Düzenleme:

  • Durdurulmasına GCC en -fpermissive hataları (#pragma müsamahakar için çalışmıyor göz ardı tanı)
  • Set: soru, bu sorunu çözecektir aşağıdakilerden herhangi bir cevap netleştirmek için C baytını geçmeyen birleşim veya alt yapı en fazla boyutu
  • C baytları tarafından kapsanmayan üyeler için bit uzunluğunun 0'a izin ver (GCC, (C-3> 0) gibi bit açı uzunluğu için matematiksel ifadelere izin verir? 8: 0;
  • C bytes tarafından kapsanmayan üyeleri devre dışı bırak anonim yapılar standart dışı olduğu

    template <int C = 3, typename T = unsigned char> union Color; 
    
    template <typename T> 
    union Color<3,T> { 
        T v[3]; 
        struct { 
        T r,g,b; 
        }; 
    }; 
    
    template <typename T> 
    union Color<4,T> { 
        T v[4]; 
        struct { 
        T r,g,b,a; 
        }; 
    }; 
    

    Not: ther araçları (yani efsanevi static_if())

+0

Doğru anlıyorsam, anonim yapıdaki üye sayısının 'C' şablon parametresiyle değişmesini istiyorsunuz? –

+0

Doğru, ideal bir şekilde, bir static_if gibi bir şey ek olarak a, x, y, z, w üyelerini açabilir C> = 4 ... – Precursor

+0

Buna ihtiyacınız var mı? T v [C]; 'şey mi yoksa sadece mi Uygulamaya dahil edilmesini beklediğiniz için bunu dahil edin – jPlatte

cevap

4

Sen C'nin farklı durumlar için yapı bir ihtisas yapabiliriz.

template <int C,typename T> 
class Color { 
    public: 
    using Values = T[C]; 

    Values &v() { return v_; } 

    const Values &v() const { return v_; } 

    T& r() { return v_[0]; } 
    T& g() { return v_[1]; } 
    T& b() { return v_[2]; } 

    template <int C2 = C, 
     typename = typename std::enable_if<(C2>3)>::type> 
    T& a() 
    { 
     return v_[3]; 
    } 

    const T& r() const { return v_[0]; } 
    const T& g() const { return v_[1]; } 
    const T& b() const { return v_[2]; } 

    template <int C2 = C, 
     typename = typename std::enable_if<(C2>3)>::type> 
    const T& a() const 
    { 
     return v_[3]; 
    } 

    private: 
    Values v_; 
}; 

Daha sonra, bu gibi kullanabilirsiniz: üye işlevlerini kullanarak bir olasılık ise

, bunu gitmek için daha iyi bir yol olacağını düşünüyorum

int main() 
{ 
    Color<3,int> c3; 
    Color<4,int> c4; 

    c3.v()[0] = 1; 
    c3.v()[1] = 2; 
    c3.v()[2] = 3; 

    std::cout << 
    c3.r() << "," << 
    c3.g() <<"," << 
    c3.b() << "\n"; 

    c4.v()[0] = 1; 
    c4.v()[1] = 2; 
    c4.v()[2] = 3; 
    c4.v()[3] = 4; 

    std::cout << 
    c4.r() << "," << 
    c4.g() << "," << 
    c4.b() << "," << 
    c4.a() << "\n"; 
} 
+0

Cevabınızdaki ayrıntıyı gerçekten takdir ediyorum - üye fonksiyonlarını kullanmakta tereddüt ettim, ancak uzmanlaşmış yapılar (kısmi şablonlama) tam ihtiyacım olan şeydi. Çok teşekkürler! – Precursor

2

Tamam, şimdi @ VaughnCato bunu benden önce yaptı, ama yine de cevabımı std::enable_if kullanarak göndereceğim. Yapı olarak Renk olarak bildirir, çünkü her şeyin herkese açık olduğu bir sınıfa sahip olmanın gerçekten bir anlamı yoktur (ve sorudaki [v içinde] veri üyesini bildirmek için iyi bir neden yoktur), biraz daha sözdizimsel şeker için şablon takma adlar ekler. ve kullanıcının şablon parametreleri için garip değerleri kullanmadığından emin olmak için static_assert'u kullanır. Aynı zamanda biraz daha farklı bir şekilde std::enable_if kullanır, bu da biraz daha okunabilir bir durumdur.

#include <type_traits> 
#include <cstdint> 

template<unsigned nChans, typename T = std::uint8_t> 
struct Color 
{ 
    static_assert(nChans >= 3 || nChans <= 4, "number of color channels can only be 3 or 4"); 
    // allow integral types only 
    //static_assert(std::is_integral<T>::value, "T has to be an integral type"); 
    // also allow floating-point types 
    static_assert(std::is_arithmetic<T>::value, "T has to be an arithmetic (integral or floating-point) type"); 

    T data[nChans]; 

    T& r() { return data[0]; } 
    T& g() { return data[1]; } 
    T& b() { return data[2]; } 

    //template<typename U = T, typename EnableIfT = std::enable_if<(nChans == 4), U>::type> // C++11 
    template<typename U = T, typename EnableIfT = std::enable_if_t<(nChans == 4), U>> // C++14 
    T& a() { return data[3]; } 

    const T& r() const { return data[0]; } 
    const T& g() const { return data[1]; } 
    const T& b() const { return data[2]; } 

    //template<typename U = T, typename EnableIfT = std::enable_if<(nChans == 4), U>::type> 
    template<typename U = T, typename EnableIfT = std::enable_if_t<(nChans == 4), U>> 
    T const& a() const { return data[3]; } 
}; 

template<typename T = std::uint8_t> using RgbColor = Color<3, T>; 
template<typename T = std::uint8_t> using RgbaColor = Color<4, T>; 
+0

Katılıyorum, bu daha güzel bir 'enable_if' stili. –