给定重载函数f1
:
void f1(int);
int f1(char);
包含成员模板X
的类模板f
:
template<class T>
struct X
{
template<class U>
static void f(T(*p)(U));
};
编译器能够从函数类型的一部分解析f1
:
X<int>::f(f1); // T = int (specified), U = char (deduced)
X<void>::f(f1); // T = void (specified), U = int (deduced)
但是,可变二进制类模板Y
在两侧都带有参数包:
template<class... T>
struct Y
{
template<class... U>
static void f(T(*...p)(U));
};
未能做同样的事情:
Y<int>::f(f1); // error
Y<void>::f(f1); // error
Y<int, void>::f(f1, f1); // error
请注意,如果参数包仅在一侧,则表示正常:
template<class... T>
struct Z1
{
template<class U>
static void f(T(*...p)(U));
};
template<class T>
struct Z2
{
template<class... U>
static void f(T(*...p)(U));
};
Z1<int>::f(f1); // ok
Z2<void>::f(f1); // ok
这显示了一个问题:当内部参数包T
仍然依赖时,无法扩展外部参数包U
。
我想当实例化Y::f
时,编译器可以将Y<int, void>
扩展为类似下面的内容:
template<class... U>
void f(int(*p0)(U0), void(*p1)(U1));
其中U0
和U1
表示参数包U
的前2个元素。
但似乎编译器(g ++ / clang)拒绝这样做并使整个p
无法使用。
在标准中它指定了这样的行为?它可能是标准缺陷还是需要改进的东西?
答案 0 :(得分:0)
我已经提取了另一个可行的代码片段,虽然仍然无法满足您的需求,但可能会引导您:
“obj.lastName”
这个void f1(int)
{
}
int f1(char)
{
return 0;
}
template <class Out, class In>
struct UniFunction
{
typedef Out fn(In);
typedef fn* ptr;
};
template<class... T>
struct Y
{
//template<class... U>
//static void f(T(*...p)(U)...);
template <class... U>
struct YY
{
static void f(typename UniFunction<T, U>::ptr...)
{
}
};
};
int main( int argc, char** argv )
{
Y<int>::YY<char>::f(f1);
return 0;
}
只是为了清晰起见,可能表明参数包的双重并行扩展并非不可能,只是一个小问题。
我认为如果你另外提供一个“模板函数”(带有typedef的结构模板),你仍然可以强制执行参数类型推导,它将从函数指针中提取(使用UniFunction
或某些东西)参数类型和返回类型。通过这样,您应该能够为type_traits
函数提供一个模板参数(kinda Y::f
),从作为函数指针的X...
中提取参数类型,然后传递它明确指向X
模板,如此处所示。