!!! SOLUTION BELOW !!!
I'm trying to extend the OpenCL wrapper CL/cl2.hpp so I can set any amount of Kernel arguments with just one call like this:
setArgs(kernel, arg1, arg2, arg3,...);
To do that I've implemented these variadic templates for setArgs:
// recursion end
void setArgs(const cl::Kernel &kernel, uint i) {}
// actual recursive function
template<typename ArgumentType, typename... ArgumentTypes>
void setArgs(const cl::Kernel &kernel, uint i, ArgumentType arg, ArgumentTypes... args) {
    kernel.setArg(i, arg);
    setArgs(kernel, i++, args...);
}
// split the argument list into head and tail
template<typename ArgumentType, typename... ArgumentTypes>
void setArgs(const cl::Kernel &kernel, ArgumentType arg, ArgumentTypes... args) {
    setArgs(kernel, 0, arg, args...);
}
// I think this should be the first called function
template<typename... ArgumentTypes>
void setArgs(const cl::Kernel &kernel, ArgumentTypes... args) {
    setArgs(kernel, 0, args...);
}
Calling it like setArgs(kernel, bufferIn, bufferOut, (cl_double)3.14) caused this error:
undefined reference to void setArgs<cl::Buffer, cl::Buffer, double>(cl::Kernel const&, cl::Buffer, cl::Buffer, double)
I'm very sorry but I'm pretty new to C++11 variadic functions and I don't get why it doesn't work. I tried fiddling around but nothing worked. The code above is the most logical I can come up with.
PS: I know it's just syntax sugar but I it would reduce redundancy in my code a lot and it's propably good to understand variadic templates ;)
!!! Solution!!!
1. Move templates to .hpp
Templates can only be implemented - that is declared AND defined in header files. So I needed to move the templates to the .hpp file and split the recursion end function definition to the .cpp file.
Thanks @NathanOliver for explaining.
2. Fix recursion abiguity
Consider the following method declarations:
// A
void setArgs(const cl::Kernel &kernel, ArgumentType arg, ArgumentTypes... args)
// B
void setArgs(const cl::Kernel &kernel, uint i, ArgumentType arg, ArgumentTypes... args)
Calling setArgs(kernel, 42, argA, argB) can match to both A and B. Thus the recursion expands to ever increasing size. This led to the following error message:
void setArgs(cl::Kernel&, ArgumentType, ArgumentTypes ...) [with ArgumentType = int; ArgumentTypes = {int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int...
fatal error: template instantiation depth exceeds maximum of 900 (use ‘-ftemplate-depth=’ to increase the maximum)
Using i as the first parameter solved this ambiguity. Now I got the following code:
kernel.hpp (excerpt):
void setArgs(uint i, cl::Kernel &kernel);
template<typename ArgumentType, typename... ArgumentTypes>
void setArgs(uint i, cl::Kernel &kernel, ArgumentType arg, ArgumentTypes... args) {
    kernel.setArg(i, arg);
    setArgs(i + 1, kernel, args...);
}
template<typename ArgumentType, typename... ArgumentTypes>
void setArgs(cl::Kernel &kernel, ArgumentType arg, ArgumentTypes... args) {
    setArgs(0, kernel, arg, args...);
}
template<typename ArgumentType, typename... ArgumentTypes>
void setArgs(cl::Kernel &kernel, ArgumentType arg, ArgumentTypes... args) {
    setArgs(0, kernel, arg, args...);
}
kernel.cpp (excerpt):
#include "kernel.hpp"
void setArgs(uint i, cl::Kernel &kernel) {}
More elegant solution as class
kernel.hpp (excerpt):
class Kernel : public cl::Kernel {
public:
    using cl::Kernel::Kernel;
    template<typename... ArgumentTypes>
    Kernel setArgs(ArgumentTypes ... args) {
        return _setArgs(args...);
    }
private :
    uint i = 0;
    template<typename ArgumentType, typename... ArgumentTypes>
    Kernel _setArgs(ArgumentType arg, const ArgumentTypes ... args) {
        setArg(i, arg);
        i++;
        return _setArgs(args...);
    }
    Kernel _setArgs();
};
kernel.cpp (excerpt):
#include "kernel.hpp"
Kernel Kernel::_setArgs() { return *this; }
Calling the functions:
Kernel kernel = Kernel(device, kernelName)
    .setArgs(argIn, argOut)
    .setArgs(moreParams);
 
    