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...

1 Answer 1

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

Sign up to request clarification or add additional context in comments.

5 Comments

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
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. Could you explain why the linker error happens? I got no idea...
@Bim: Updated answer and demo.
Thanks. Works and is pretty slick now!
And with c++14, you may even get rid of -> decltype(std::get<I>(data)) with decltype(auto).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.