指向模板成员函数的指针类型不匹配
Type mismatch of pointer to template member function
我正在关注 this code snippet 这使得将成员函数传递给需要 C 风格回调的接口变得更容易(也就是说,接口需要一个指向回调的函数指针,以及一个 void*
指向用户数据的指针,该数据将依次传递给回调)。实际上,我想将 Helper::M
转换为下面的 Helper::V
。
我正在尝试修改代码段以自动推断模板参数。这是我目前的尝试。
#include <iostream>
template <typename R, typename T, typename... Args>
struct Helper {
using V = R (*)(void*, Args...);
using M = R (T::*)(Args...);
template <M m>
static R Fn(void* data, Args... args) {
return (static_cast<T*>(data)->*m)(std::forward<Args...>(args...));
}
};
template <typename R, typename T, typename... Args>
typename Helper<R, T, Args...>::V Cast(R (T::*m)(Args...)) {
return Helper<R, T, Args...>::template Fn<m>;
}
int CIntf(void* data, int (*f)(void*, int)) { return f(data, 1); }
struct UserData {
int x;
int Add(int y) { return x + y; }
};
int main(int argv, char** argc) {
UserData data = {4};
// Explicit parameters; works.
std::cout << CIntf(&data, Helper<int, UserData, int>::Fn<&UserData::Add>)
<< "\n";
// Deduced parameters; fails.
std::cout << CIntf(&data, Cast(&UserData::Add)) << "\n";
return 0;
}
我尝试用 gcc -std=c++11 -lstdc++
编译。显式参数方法工作正常,但推导参数方法给出以下错误:
tmp.cc: In instantiation of ‘typename Helper<R, T, Args>::V Cast(R (T::*)(Args ...)) [with R = int; T = UserData; Args = {int}; typename Helper<R, T, Args>::V = int (*)(void*, int)]’:
tmp.cc:30:58: required from here
tmp.cc:15:42: error: no matches converting function ‘Fn’ to type ‘using V = int (*)(void*, int) {aka int (*)(void*, int)}’
return Helper<R, T, Args...>::template Fn<m>;
^~~~~
tmp.cc:8:12: note: candidate is: template<int (UserData::* m)(int)> static R Helper<R, T, Args>::Fn(void*, Args ...) [with R (T::* m)(Args ...) = m; R = int; T = UserData; Args = {int}]
static R Fn(void* data, Args... args) {
请注意,它正确推导了模板参数,但无法将 Helper<int, UserData, int>::Fn<m>
转换为 int (*)(void*, int)
;为什么?同样的转换在显式情况下成功了(除非 m
与 &UserData::Add
有某种不同)。
很遗憾,您必须为此使用宏:
#define makeFunc(method) &Helper<decltype(method)>::Fn<method>
并像这样重新定义您的助手以使其工作:
template <typename T>
struct Helper;
template <typename R, typename T, typename... Args>
struct Helper<R(T::*)(Args...)>
你不能为此使用演绎的原因是演绎只适用于 运行 时间值的函数参数。你需要使用一个方法的地址作为模板参数,它应该是一个编译时值。
所以当你这样做时:
return Helper<R, T, Args...>::template Fn<m>;
您正在传递 运行 时间值 m
作为模板参数,这是不可能的。
作为参考,这里是使用宏的完整代码。另请注意,在原始代码中使用 std::forward
对于多个参数 (see this answer) 是不正确的。
#include <iostream>
#include <utility>
template <typename T>
struct Helper;
template <typename R, typename T, typename... Args>
struct Helper<R (T::*)(Args...)> {
template <R (T::*m)(Args...)>
static R Fn(void* t, Args... args) {
return (static_cast<T*>(t)->*m)(std::forward<Args>(args)...);
}
};
#define VOID_CAST(m) &Helper<decltype(m)>::Fn<m>
struct UserData {
int x;
int Add1(int y) { return x + y; }
int Add2(int y, int z) { return x + y + z; }
};
int Call1(void* data, int (*f)(void*, int)) { return (*f)(data, 1); }
int Call2(void* data, int (*f)(void*, int, int)) { return (*f)(data, 1, 2); }
int main() {
UserData data = {4};
std::cout << Call1(&data, VOID_CAST(&UserData::Add1)) << "\n";
std::cout << Call2(&data, VOID_CAST(&UserData::Add2)) << "\n";
return 0;
}
我正在关注 this code snippet 这使得将成员函数传递给需要 C 风格回调的接口变得更容易(也就是说,接口需要一个指向回调的函数指针,以及一个 void*
指向用户数据的指针,该数据将依次传递给回调)。实际上,我想将 Helper::M
转换为下面的 Helper::V
。
我正在尝试修改代码段以自动推断模板参数。这是我目前的尝试。
#include <iostream>
template <typename R, typename T, typename... Args>
struct Helper {
using V = R (*)(void*, Args...);
using M = R (T::*)(Args...);
template <M m>
static R Fn(void* data, Args... args) {
return (static_cast<T*>(data)->*m)(std::forward<Args...>(args...));
}
};
template <typename R, typename T, typename... Args>
typename Helper<R, T, Args...>::V Cast(R (T::*m)(Args...)) {
return Helper<R, T, Args...>::template Fn<m>;
}
int CIntf(void* data, int (*f)(void*, int)) { return f(data, 1); }
struct UserData {
int x;
int Add(int y) { return x + y; }
};
int main(int argv, char** argc) {
UserData data = {4};
// Explicit parameters; works.
std::cout << CIntf(&data, Helper<int, UserData, int>::Fn<&UserData::Add>)
<< "\n";
// Deduced parameters; fails.
std::cout << CIntf(&data, Cast(&UserData::Add)) << "\n";
return 0;
}
我尝试用 gcc -std=c++11 -lstdc++
编译。显式参数方法工作正常,但推导参数方法给出以下错误:
tmp.cc: In instantiation of ‘typename Helper<R, T, Args>::V Cast(R (T::*)(Args ...)) [with R = int; T = UserData; Args = {int}; typename Helper<R, T, Args>::V = int (*)(void*, int)]’:
tmp.cc:30:58: required from here
tmp.cc:15:42: error: no matches converting function ‘Fn’ to type ‘using V = int (*)(void*, int) {aka int (*)(void*, int)}’
return Helper<R, T, Args...>::template Fn<m>;
^~~~~
tmp.cc:8:12: note: candidate is: template<int (UserData::* m)(int)> static R Helper<R, T, Args>::Fn(void*, Args ...) [with R (T::* m)(Args ...) = m; R = int; T = UserData; Args = {int}]
static R Fn(void* data, Args... args) {
请注意,它正确推导了模板参数,但无法将 Helper<int, UserData, int>::Fn<m>
转换为 int (*)(void*, int)
;为什么?同样的转换在显式情况下成功了(除非 m
与 &UserData::Add
有某种不同)。
很遗憾,您必须为此使用宏:
#define makeFunc(method) &Helper<decltype(method)>::Fn<method>
并像这样重新定义您的助手以使其工作:
template <typename T>
struct Helper;
template <typename R, typename T, typename... Args>
struct Helper<R(T::*)(Args...)>
你不能为此使用演绎的原因是演绎只适用于 运行 时间值的函数参数。你需要使用一个方法的地址作为模板参数,它应该是一个编译时值。
所以当你这样做时:
return Helper<R, T, Args...>::template Fn<m>;
您正在传递 运行 时间值 m
作为模板参数,这是不可能的。
作为参考,这里是使用宏的完整代码。另请注意,在原始代码中使用 std::forward
对于多个参数 (see this answer) 是不正确的。
#include <iostream>
#include <utility>
template <typename T>
struct Helper;
template <typename R, typename T, typename... Args>
struct Helper<R (T::*)(Args...)> {
template <R (T::*m)(Args...)>
static R Fn(void* t, Args... args) {
return (static_cast<T*>(t)->*m)(std::forward<Args>(args)...);
}
};
#define VOID_CAST(m) &Helper<decltype(m)>::Fn<m>
struct UserData {
int x;
int Add1(int y) { return x + y; }
int Add2(int y, int z) { return x + y + z; }
};
int Call1(void* data, int (*f)(void*, int)) { return (*f)(data, 1); }
int Call2(void* data, int (*f)(void*, int, int)) { return (*f)(data, 1, 2); }
int main() {
UserData data = {4};
std::cout << Call1(&data, VOID_CAST(&UserData::Add1)) << "\n";
std::cout << Call2(&data, VOID_CAST(&UserData::Add2)) << "\n";
return 0;
}