Search code examples
c++templateslanguage-lawyervariadic-templates

What is wrong with my variadic-template-based wrapper function?


I am currently working on a program in which I want to wrap some Vulkan functions in an easier to use variadic template¹. When I attempt to do so, however, I am encountering an error from my compiler (I tried both GCC and clang on Linux with both C++14 and C++17 flags). The following toy example demonstrates the error with similar constructions:

#include <iostream>

int exampleFunction(const char *str, int a, int b){ //a const char* is used instead of std::string in order to avoid worrying about the fact that std::string is a class with overridden copying and move semantics
    std::cout << str << ": " << a << std::endl;
    std::cout << str << ": " << b << std::endl;
    return a+b; //to avoid non-void return type, as is the case in my real program
}

template<typename T, typename U, typename ... Args>
void functionTemplate(U (*function)(Args...,int,T), Args... args){
    function(args..., 1, 2);
}

int main() {
    functionTemplate(&exampleFunction, "label")
    return 0;
}

When I compile this program in clang 8.0.1 to the x86_64-pc-linux-gnu target I get the following errors:

<path redacted>/main.cpp:15:5: error: no matching function for call to 'functionTemplate'
    functionTemplate(&exampleFunction, "label")
    ^~~~~~~~~~~~~~~~
<path redacted>/main.cpp:10:6: note: candidate template ignored: could not match 'int' against 'const char *'
void functionTemplate(U (*function)(Args...,int,T), Args... args){

I expect the program to compile correctly and output the following:

label: 1
label: 2

Why does this not happen? A good answer will give plenty of theory explaining why, and not just how to fix it. I am asking this question primarily to fix the hole in my C++ knowledge where I don't know why this isn't working. There are alternatives than this style of construction in the real program.

¹: It is possible that the C++ wrapper on Vulkan already does this, but I am using the C API now in order to learn Vulkan better. This issue that I encountered while using the C API shows a gap in my C++ knowledge that I want to fix.


Solution

  • Main issue with

    template<typename T, typename U, typename ... Args>
    void functionTemplate(U (*)(Args..., int, int), Args...);
    

    is that T is non deducible, you you don't provide it.

    Second issue is that deducing rules for variadic template is "limited" and Args isn't deduced as expected for U (*)(Args..., int, T). it is deduced as empty pack (which lead to a non deduced/matching T). First Args also conflicts with seconds Args which is deduced as [concst char*].