C++ 模板参数推导相关问题

写项目的时候遇到相关问题, image.png 上面注释的代码是编译不了的。

函数原型

WINBASEAPI
HANDLE
WINAPI
CreateFileA(
    _In_ LPCSTR lpFileName,
    _In_ DWORD dwDesiredAccess,
    _In_ DWORD dwShareMode,
    _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    _In_ DWORD dwCreationDisposition,
    _In_ DWORD dwFlagsAndAttributes,
    _In_opt_ HANDLE hTemplateFile
    );

如果不加类型强制转换的话,也就是注释的代码 自动推导的类型如下

void * __ptr64 char [9]
unsigned long
int
int
int
int
int

很显然与函数原型不匹配。 下面是正确的推导。

void * __ptr64 char [9]
unsigned long
unsigned long
struct _SECURITY_ATTRIBUTES * __ptr64
unsigned long
unsigned long
void * __ptr64

好像不加强转是不行的

完整代码

#include <iostream>
#include <windows.h>
using namespace std;

template <typename Ret, typename... Args>
static inline auto spoof_call(
	const void* trampoline,
	Ret(*fn)(Args...), // 提供一个已有函数原型推导参数类型Args和返回类型Ret
	Args... args)
	-> Ret {
  cout << typeid(Ret).name() << " ";
  Ret r = 0;
  return r;
} 

// 打印出参数包中参数被自动推导的类型
template<typename Arg>
void print_param_packedtype(const Arg& arg){
    //std::cout<<arg<<std::endl;
  cout << typeid(Arg).name() << " ";
}

template<typename Arg,typename ...Args>
void print_param_packedtype(const Arg& arg,const Args& ...args){
    //std::cout<<arg<<" ";
  cout << typeid(Arg).name() << endl;
    print_param_packedtype(args...); //递归解包
}
//


int main() {
  spoof_call(nullptr, &CreateFileA, "test.txt", (GENERIC_READ | GENERIC_WRITE),
             (DWORD)(FILE_SHARE_WRITE | FILE_SHARE_READ),
             (LPSECURITY_ATTRIBUTES)NULL, (DWORD)CREATE_ALWAYS,
             (DWORD)FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);

  print_param_packedtype("test.txt", (GENERIC_READ | GENERIC_WRITE),
                         (FILE_SHARE_WRITE | FILE_SHARE_READ),
                        NULL, CREATE_ALWAYS,
                         FILE_ATTRIBUTE_NORMAL, NULL);
  return 0;
}

但是他娘的模板参数推导是可以隐式转换的。

#include <iostream>
#include <windows.h>
using namespace std;

template<typename _T = float>
void test(_T p1) {
  cout << p1 << " ";
}

template<typename _T = DWORD>
void test2(_T p1) {
  cout << p1 << " ";
}

template<typename _T = HANDLE>
void test3(_T p1) {
	cout << p1 << " ";
}

int main() {
  test(4.0);// double 隐式转float
  test2(1);// int隐式转DWORD
  test3(0);// int转void*
  return 0;
}
#include <iostream>
#include <windows.h>
using namespace std;

template <typename Ret, typename... Args>
void test(Ret(*fn)(Args...),Ret k) {// Ret类型不能由隐式转换了,原因不知道,反正编译器这样设计
  cout << typeid(Ret).name();
  cout << endl;
  cout << typeid(k).name();
}


int main() {
  //test(&CreateFileA,0); //error
  test(&CreateFileA,(HANDLE)0);
  return 0;
}