在另一个模板函数的定义中解压函数参数类型

Unpack function parameter types in the definition of another template function

我正在制作一个 class 模板来编码函数指针。该函数可以有任何结果类型和参数的数量/类型。这是我的:

LPVOID EncodePtr(LPVOID ptr) {
  // Encode...
  return ptr;
}

LPVOID DecodePtr(LPVOID ptr) {
  // Decode...
  return ptr;
}

template<class T>
class encoded_ptr {
public:

  typedef encoded_ptr<T> _Myt;

  encoded_ptr() {
    ptr_ = (T*)EncodePtr(nullptr);
  }

  // Irresponsible?
  template<class _OtherType>
  encoded_ptr(_OtherType ptr) {
    ptr_ = (T*)DecodePtr((LPVOID)ptr);
  }

  ~encoded_ptr() {
    ptr_ = (T*)EncodePtr(nullptr);
  }

  // Makes it possible to call the function directly
  template<class... _Args>
  typename std::result_of<T*(_Args...)>::type operator()(_Args... _Ax) {
    T* fn = get();

    return fn(_Ax...);
  }

  T* get() const {
    return (T*)DecodePtr((LPVOID)ptr_);
  }

  bool is_set() {
    return (get() != nullptr);
  }

private:
  T* ptr_;
};

它按预期工作。例如:

encoded_ptr<decltype(MessageBoxA)> MsgBox;
MsgBox = &MessageBoxA; // Could also initialize in the constructor

// (HWND)0 is justified by the actual problem in the question
MsgBox((HWND)0, "Test message!", "Test", 0);

第一个问题是括号运算符 () 的声明方式不允许 Visual Studio 的 IntelliSense 发挥其魔力并给我有关函数参数的提示:

template<class... _Args>
typename std::result_of<T*(_Args...)>::type operator()(_Args... _Ax) {
  T* fn = get();

  return fn(_Ax...);
}

我不想使用 (_Args... _Ax),而是想解压实际的函数参数,以便 IntelliSense 可以正确给出提示。

当前行为是:

预期行为是:

第二个问题是这样调用函数,编译器不做基本转换,迫使我将NULL转换为(void*)NULL0转换为(HWND)0, 等。当使用带有很多参数的函数时,这很烦人。

可能在实现中有一些错误,但我不是模板专家。另外,不知道题名对不对

感谢任何帮助。

编辑:

到目前为止我尝试了什么(@OlegBogdanov 的建议):

template<class T, class... Args>
class encoded_ptr;

template<class T, class... Args>
class encoded_ptr<T(Args...)> {
public:

  typedef encoded_ptr<T> _Myt;

  using Fptr = T(*)(Args...);
  encoded_ptr(Fptr ptr) {
    ptr_ = (Fptr)EncodePtr((LPVOID)ptr);
  }

  // Makes it possible to call the function directly
  typename T operator()(Args... _Ax) {
    Fptr fn = get();

    return fn(std::forward<Args>(_Ax)...);
  }

  Fptr get() const {
    return (T*)DecodePtr((LPVOID)ptr_);
  }

  bool is_set() {
    return (get() != nullptr);
  }

private:
  Fptr ptr_;
};

结果:无法实例化/使用构造函数:Incomplete type is not allowed

编辑:

这是正确的方向,问题是调用约定。

已更改:

class encoded_ptr<T(Args...)>class encoded_ptr<T(__stdcall)(Args...)>,以及

using Fptr = T(*)(Args...)using Fptr = T(__stdcall*)(Args...)

我正在尝试检测调用约定而不是对其进行硬编码。

我认为您对

的期望
template<class... _Args>
typename std::result_of<T*(_Args...)>::type operator()(_Args... _Ax) {
  T* fn = get();

  return fn(_Ax...);
}

错了。它完全忽略了你的目标函数参数列表(你使用了穷人类型的擦除)并传递(我想使用单词 'forwards' 但那是不准确的)无论调用者给出什么。因此 0 in

MsgBox(0, "Test message!", "Test", 0);

被推断为 int 并且您必须将其转换为 HWND,否则编译器将无法猜测它。

你真正在做的是重新发明 std::function 或它上面的某种包装器。

如果您真的认为 std::function 不足以满足您的需求,您将不得不复制其部分实现,即您至少需要

    template<class R, class... Args>
    class encoded_ptr; // leaving this undefined

    template<class R, class... Args>
    class encoded_ptr<R(Args...)> {

    using Fptr = R(*)(Args...);
    encoded_ptr(Fptr ptr) {
        ptr_ = (T*)DecodePtr((LPVOID)ptr);
    }
    ...

在您的类型中捕获参数列表

并且调用运算符将​​重新使用它而不是随机键入传递的参数:

// this must not be here -> template<class... _Args>
R operator()(Args... _Ax) {
  T* fn = get()

  return fn(std::forward<Args>(_Ax)...);
}

编辑:

你不能存储但是 T* 了,T 只是一个 return 类型,按 Fptr

存储