Search code examples
c++templateswinapidecltype

Incorrect argument to decltype


I asked two days ago about creating threads to run non-static class methods with the Win32 API, and I almost got a solution but there is something confusing me, so I'm asking this question before posting the answer in my previous question.

I'm trying to use this code to thread a function with an unknown return type:

template <class R, R func() >
unsigned int usualfunc() {
   func();
   return 1;
}

template <class R>
int Start(R(*func)()) {
   typedef decltype(&usualfunc<int, func>) D; // I get the error here , I can't get the address of the template function directly I need this
   D p = &usualfunc<R, func>;
   uintptr_t add = (uintptr_t)p;
   CreateThread(0, 0, (LPTHREAD_START_ROUTINE)add, 0, 0, 0);
   func();
   return 1;
}

int main() {
   Start(ltest);
}

When I try to compile the above code, I get :

error 3556 'usualfunc': incorrect argument to 'decltype'

The error description is described on MSDN:

Compiler Error C3556

However, I tried another code before this, and it works just fine, but I wasn't very good with the syntax:

template <class R, R func() >
unsigned int usualfunc() {
   func();
   return 1;
}

 template <class R,R func()>
int Start() {
   typedef decltype(&usualfunc<int, func>) D; // works well
   D p = &usualfunc<R, func>;
   uintptr_t add = (uintptr_t)p;
   CreateThread(0, 0, (LPTHREAD_START_ROUTINE)add, 0, 0, 0);
   func();
   return 1;
}

int main() {
   Start<int,ltest>(); // works
}

I know this code is enough, but I'd like to use Start(ltest) instead of Start<int,ltest>().

Note: no one say that I should use the function as parameter in usualfunction, I'm using it as a template parameter because CreateThread() can't pass a function as a parameter.


Solution

  • Template parameters must be known at compile-time. However you attempt to use the normal function parameter func as a template argument.

    In the second code you give a template parameter as the template argument, which is fine.

    Your first code is wrong for a similar reason as this code:

    template<int X> void f() { }
    
    int main(int argc, char **argv) { f<argc>(); }
    

    although the error message is a bit more obscure.


    Since C++17 you can get the syntax you want by making this modification to your second code:

    template <auto func>
    int Start() {
        using R = decltype(func());
        // proceed as before...
    

    and call it as Start<ltest>();.

    Prior to C++17 you could use a macro with your second code:

    #define START(func) Start<decltype(func()), func>