可以用内部参数包扩展外部参数包吗?

时间:2016-09-02 02:58:47

标签: c++ templates c++11 language-lawyer variadic-templates

给定重载函数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));

其中U0U1表示参数包U的前2个元素。

但似乎编译器(g ++ / clang)拒绝这样做并使整个p无法使用。 在标准中它指定了这样的行为?它可能是标准缺陷还是需要改进的东西?

1 个答案:

答案 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模板,如此处所示。