从variadic模板解包参数

bl4*_*0ne 3 c++ templates

对于我的一个项目,我需要使用可变参数模板.一切都运作良好,除了参数的解包.

这是电话

Shader<GL_VERTEX_SHADER> vert(vertexShaderSource);
Shader<GL_FRAGMENT_SHADER> frag(fragmentShaderSource);
Program prog(vert, frag);
Run Code Online (Sandbox Code Playgroud)

以及导致问题的类

class Program
{
    public:
        template <class... Args>
        Program(Args... args) :
            program_(glCreateProgram())
        {         
            auto shaders {{args...}};

            std::for_each(shaders.begin(), shaders.end(), [this](auto s)       
            {
                std::cout << "glAttachShader\n";
                glAttachShader(program_, s.get_shader());
            });
        }
};
Run Code Online (Sandbox Code Playgroud)

而错误

fatal error: cannot deduce type for variable 'shaders' with type 'auto' from nested initializer list
    auto shaders {{args...}};
Run Code Online (Sandbox Code Playgroud)

我尝试了几件事,比如

auto shaders = {args...};
auto shaders = {{args...}};
auto shaders {args...};    
Run Code Online (Sandbox Code Playgroud)

但没有任何作用.

这是Shader类,以防万一

template <GLenum type>
class Shader
{
    public:
        Shader(std::string const &source)
        {
            char const *src = source.c_str();
            shader_ = glCreateShader(type);
            glShaderSource(shader_, 1, &src, NULL);
            glCompileShader(shader_);
        }

        ~Shader()
        {
            glDeleteShader(shader_);
        }

        inline GLuint get_shader()
        {
            return shader_;
        }

    private:
        GLuint shader_;
};
Run Code Online (Sandbox Code Playgroud)

谢谢!

eti*_*ray 6

这不是关于可变参数模板解包的.问题是在声明着色器时,您需要告诉它的类型.它是矢量,数组,元组等吗?由于您正在使用可变参数模板,因此我猜测着色器可以有不同的类型.然后你必须使用元组.

auto shaders = std::make_tuple(args...);
Run Code Online (Sandbox Code Playgroud)

迭代一个元组并不像stl容器那样微不足道.这是一个使用递归的例子.

template <size_t i = 0,
          class Fun,
          class Tuple,
          size_t N = std::tuple_size<typename std::decay<Tuple>::type>::value,
          std::enable_if_t<i >= N>* = nullptr> // if i >= N
void tuple_for_each(Tuple&& t, Fun f) {} // end case

template <size_t i = 0,
          class Fun,
          class Tuple,
          size_t N = std::tuple_size<typename std::decay<Tuple>::type>::value,
          std::enable_if_t<i < N>* = nullptr> // if i < N
void tuple_for_each(Tuple&& t, Fun f) {
  f(std::get<i>(std::forward<Tuple>(t))); // current iteration
  tuple_for_each<i+1>(std::forward<Tuple>(t), std::move(f)); // call next
}
Run Code Online (Sandbox Code Playgroud)

总的来说,它非常直观,我们从i = 0开始,调用f()然后使用递归来遍历每个i直到N. C++ 14允许你避免使用std :: integer_sequence进行递归,你可以搜索它.

如果您对此&&胡说八道感到疑惑,我建议您阅读有关Universal References的内容.简而言之,它允许您使用引用来防止复制参数,同时可以处理r值.我建议你在程序构造函数中为Args做同样的事情.

然后我们可以使用tuple_for_each来做

tuple_for_each(shaders, [this](auto s) {
  std::cout << "glAttachShader\n";
  glAttachShader(program_, s.get_shader());
});
Run Code Online (Sandbox Code Playgroud)