1

I have a variadic template class "InterleavedAttribute" and now I want to want some runtime information ("AttributeTypeInfo") about the types in the template. I wanted to fill a static const array in the template class ("attributeInfo") and later access that array using an index for the individual information at runtime, like object.typeInfo(2), but I can not figure out how. Here's what I have:

#include <iostream>

template <typename TYPE> struct GLTypeInfo;

template <>
struct GLTypeInfo<char> { static constexpr unsigned int glType = 0; };

template <>
struct GLTypeInfo<int> { static constexpr unsigned int glType = 1; };

template <>
struct GLTypeInfo<float> { static constexpr unsigned int glType = 2; };

//---------------------------------------------------------------------------

struct AttributeTypeInfo
{
    unsigned int nrOfComponents;
    unsigned int glType;
    unsigned int bytesPerComponent;
    unsigned int bytesPerAttribute;

    constexpr AttributeTypeInfo(unsigned int _nrOfComponents, unsigned int _glType, unsigned int _bytesPerComponent, unsigned int _bytesPerAttribute)
        : nrOfComponents(_nrOfComponents), glType(_glType), bytesPerComponent(_bytesPerComponent), bytesPerAttribute(_bytesPerAttribute)
    {}       
};

template <typename T>
struct TypeInfoFactory
{
    static unsigned int constexpr extent = std::is_array<T>::value ? std::extent<T>::value : 1;
    using type = typename std::conditional<std::is_array<T>::value, typename std::remove_extent<T>::type, T>::type;
    static constexpr AttributeTypeInfo typeInfo = AttributeTypeInfo(extent, GLTypeInfo<type>::glType, sizeof(type), sizeof(type) * extent);
};

//---------------------------------------------------------------------------

template <typename TYPE, typename ...P> struct InterleavedAttribute
{
    static constexpr unsigned int nrOfAttributes = sizeof...(P)+1;
    //static constexpr AttributeTypeInfo attributeInfo[sizeof...(P)+1] = { ??? }; // <-- How do I fill this...
    TYPE data;
    InterleavedAttribute<P...> next;
    InterleavedAttribute() {}
    InterleavedAttribute(const TYPE & value, const P &... p) : data(value), next(p...) {}
    //static constexpr AttributeTypeInfo typeInfo(unsigned int index) { return attributeInfo[index]; } // ...so I can call this later?
};

template <typename TYPE> struct InterleavedAttribute<TYPE>
{
    static constexpr unsigned int nrOfAttributes = 1;
    static constexpr AttributeTypeInfo attributeInfo[1] = { TypeInfoFactory<TYPE>::typeInfo };
    TYPE data;
    InterleavedAttribute() {}
    InterleavedAttribute(const TYPE & value) : data(value) {}
    static constexpr AttributeTypeInfo typeInfo(unsigned int index) { return attributeInfo[0]; }
};

int main() {
    InterleavedAttribute<int> ia1(5);
    std::cout << "Numer of attributes: " << ia1.nrOfAttributes << std::endl;
    std::cout << "Attribute 0, glType: " << ia1.typeInfo(0).glType << std::endl;

    InterleavedAttribute<float, int, char> ia3(1.2, 3, 'a');
    std::cout << "Numer of attributes: " << ia3.nrOfAttributes << std::endl;
    //std::cout << "Attribute 0, glType: " << ia3.typeInfo(0).glType << std::endl; <-- Trying to get type information here
}

The code is on Coliru here. I've found this answer, and it is close, but I still can not really figure out how to get what I want...

Community
  • 1
  • 1
Bim
  • 1,008
  • 1
  • 10
  • 29

1 Answers1

2

You may do the following with std::tuple:

template <typename ...Ts> struct InterleavedAttribute
{
    static constexpr unsigned int nrOfAttributes = sizeof...(Ts);
    static constexpr AttributeTypeInfo attributeInfo[sizeof...(Ts)] = {
        TypeInfoFactory<Ts>::typeInfo...
    };
    std::tuple<Ts...> data;

    InterleavedAttribute() {}
    InterleavedAttribute(const Ts&... args) : data(args...) {}
    static constexpr AttributeTypeInfo typeInfo(unsigned int index) {
        return attributeInfo[index];
    }

    template <unsigned int I>
    auto attribute() -> decltype(std::get<I>(data)) { return std::get<I>(data); }
    template <unsigned int I>
    auto attribute() const -> decltype(std::get<I>(data)) { return std::get<I>(data); }
};

// odr-used, so definition required for linker.
template <typename ...Ts> 
constexpr AttributeTypeInfo InterleavedAttribute<Ts...>::attributeInfo[sizeof...(Ts)];

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Damn. I was too quick. I need the first TYPE template parameter for accessing the data. This does not work for me: ia3.typeInfo(i).glType. New code is [here](http://coliru.stacked-crooked.com/a/216d4af2b5660024) – Bim Jul 20 '16 at 13:22
  • Thanks, but that uses Boost. I was trying to use the std lib only. In the meantime I have converted your code using tuples to return the internal data too and [it's so much prettier](http://coliru.stacked-crooked.com/a/0d972773b6a82ba8). Could you explain why the linker error happens? I got no idea... – Bim Jul 20 '16 at 16:05
  • @Bim: Updated answer and demo. – Jarod42 Jul 20 '16 at 17:27
  • Thanks. Works and is pretty slick now! – Bim Jul 20 '16 at 17:41
  • And with c++14, you may even get rid of `-> decltype(std::get(data))` with `decltype(auto)`. – Jarod42 Jul 20 '16 at 17:45