在可变参数模板类中初始化静态数组

Posted

技术标签:

【中文标题】在可变参数模板类中初始化静态数组【英文标题】:Initialize static array in variadic template class 【发布时间】:2016-07-20 11:13:14 【问题描述】:

我有一个可变参数模板类“InterleavedAttribute”,现在我想要一些关于模板中类型的运行时信息(“AttributeTypeInfo”)。我想在模板类(“attributeInfo”)中填充一个静态 const 数组,然后在运行时使用单个信息的索引来访问该数组,例如 object.typeInfo(2),但我不知道如何。这是我所拥有的:

#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

代码位于 Coliru here。 我找到了this 的答案,而且很接近,但我仍然无法真正弄清楚如何得到我想要的......

【问题讨论】:

【参考方案1】:

您可以使用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

【讨论】:

该死的。我太快了。我需要第一个 TYPE 模板参数来访问数据。这对我不起作用:ia3.typeInfo(i).glType。新代码是here 谢谢,但这使用了 Boost。我试图只使用标准库。同时,我也使用元组转换了您的代码以返回内部数据和it's so much prettier。您能解释一下为什么会发生链接器错误吗?我不知道... @Bim:更新了答案和演示。 谢谢。工作,现在很漂亮! 而使用 c++14,您甚至可以使用 decltype(auto) 摆脱 -&gt; decltype(std::get&lt;I&gt;(data))

以上是关于在可变参数模板类中初始化静态数组的主要内容,如果未能解决你的问题,请参考以下文章

如何通过可变参数模板将多个构造函数参数转发到数组初始值设定项列表?

c ++:使用模板在类中定义可变长度数组

如何在 C++ 类中初始化可变大小数组?

可变参数模板

将可变参数模板类的模板参数解包为常量和常量数组

java泛型中可变参数的是使用