【问题标题】:Can outer parameter pack be expanded with inner parameter pack to be deduced?外参数包可以用内参数包展开推导吗?
【发布时间】:2017-01-10 01:18:24
【问题描述】:

给定重载函数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&lt;int, void&gt; 被实例化时,编译器可以将 Y::f 扩展为如下所示:

template<class... U>
void f(int(*p0)(U0), void(*p1)(U1));

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

但编译器(g++/clang)似乎拒绝这样做,并留下整个 p 未使用。 它在标准中的什么地方指定了这种行为?可能是标准缺陷还是需要改进的地方?

【问题讨论】:

  • 我认为问题在于替换了外包装的明确指定的参数。由于那时内包装仍然是空的,因此在扩展过程中会出现尺寸不匹配的情况。但是我不记得这里的规则。
  • 我认为这里适用的规则是“通过包扩展扩展的所有参数包都应指定相同数量的参数。”

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


【解决方案1】:

我提取了另一个有效的代码 sn-p,虽然仍然不能满足您的需求,但可能会导致您有所收获:

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;
}

这个UniFunction只是为了清楚起见,也许表明参数包的双重并行扩展并非不可能,只是一个小问题。

我认为,如果您另外提供一个“模板函数”(带有 typedefs 的结构模板),它将从函数指针中提取(使用type_traits 或其他东西)参数类型和返回类型,我认为您仍然可以强制执行参数类型推导。有了它,您应该能够只为Y::f 函数提供一个模板参数(有点像X...),从X 作为函数指针中提取参数类型,然后将其显式传递给YY 模板,如图所示。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2015-05-19
  • 2014-09-25
  • 2019-02-09
  • 2022-01-08
  • 2018-03-04
  • 2017-06-22
  • 1970-01-01
相关资源
最近更新 更多