0

!!! 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);
Community
  • 1
  • 1

0 Answers0