模板类的变异模板

时间:2014-09-15 19:27:54

标签: c++ templates variadic-templates

我有一个结构,定义如下:

template<typename T>
struct Variable
{
    char *name;

    constexpr Variable(char *setName) : name(setName)
    {

    }
};

我想创建一个类,其模板参数是这些结构的列表。到目前为止,我能得到的最接近的是:

template<template<typename TF> Variable First, template<TA...> typename Variable ... Args>
class UniformBuffer
{
};

UniformBuffer可能会声明如下:

// vec3 and vec4 are types defined elsewhere
UniformBuffer light<Variable<vec3>("location"), Variable<vec4>("rotation"), Variable<float>("intensity")>;

不幸的是,这不会编译,在“变量”之前给出错误“预期'类'”(尽管在其中放置“class”只会产生另一个错误,说它在'变量'之后预期'&gt;' )。即使查看关于可变参数模板的各种其他有趣的问题,我似乎也无法找到答案。我正在尝试做什么的正确语法是什么?

3 个答案:

答案 0 :(得分:3)

看来你正在寻找专业化:

template<typename First, typename... Args>
class UniformBuffer;

template<typename First, typename... Args>
class UniformBuffer<Variable<First>,Variable<Args>...>
{
};

Live example

答案 1 :(得分:1)

您不能将Variable的对象作为模板参数传递,因为它无法在编译时推断出来。

Here是一个解释

的答案

答案 2 :(得分:1)

不允许在模板参数中传递类实例,因为模板参数需要编译时解析的东西(如常量,函数名,类型)。

不幸的模板参数不能是字符串文字。

您可以做的是将这些实例传递给辅助函数,从中可以根据这些实例的类型生成类似tuple的对象。

template <typename T>
struct Variable
{
    typedef T Type;
    const char *name;
    T val;
    constexpr Variable (const char *setName) : name(setName) {}
    operator T () const { return val; }
    operator T & () { return val; }
};

template <typename... V> UniformBuffer<V...> MakeUniformBuffer (V... args) {
    return UniformBuffer<V...>(args...);
}

{
    Variable<vec3> loc("location");
    Variable<vec4> rot("rotation");
    Variable<float> amp("intensity");
    auto ub = MakeUniformBuffer(loc, rot, amp);
...
}

MakeUniformBuffer将实例传递给UniformBuffer的构造函数。 UniformBuffer必须解压缩变量模板参数。

template <typename... V> class UniformBuffer;

template <typename V>
struct UniformBuffer <V> {
    V val;
    UniformBuffer(V v) : val(v) {}
...
};

template <typename V, typename... VV>
struct UniformBuffer<V, VV...> {
    V val;
    UniformBuffer<VV...> ub;
    UniformBuffer(V v, VV... rest) : val(v), ub(rest...) {}
...
};

可以在UniformBuffer上实现set和get方法,以按名称检索缓冲区元素。下面是如何实现get方法的说明:

template <typename V>
struct UniformBuffer <V> {
...
    typename V::Type get (const Variable<typename V::Type> &v) {
        if (v.name != val.name) throw v.name;
        return val;
    }
    template <typename R> R get (const Variable<R> &v) {
        throw v.name;
        return R();
    }
};

template <typename V, typename... VV>
struct UniformBuffer<V, VV...> {
...
    typename V::Type get (const Variable<typename V::Type> &v) {
        if (v.name != val.name) return ub.get(v);
        return val;
    }
    template <typename R> R get (const Variable<R> &v) {
        return ub.get(v);
    }
};

{
...
    auto ub = MakeUniformBuffer(loc, rot, amp);
    auto r = ub.get(rot);
...
}