具有多个包的参数包匹配规则

Tra*_*kel 6 c++ templates language-lawyer variadic-templates c++11

我正在尝试编写一个函数,它使用参数包和一些标准匹配规则来获取另一个函数.举个例子:

template <typename... TListElems, typename... TVectorElems>
void goal(void (*fn)(std::list<TListElems>..., std::vector<TVectorElems>...));
Run Code Online (Sandbox Code Playgroud)

为了消除歧义TListElemsTVectorElems,我增加了一些std::tuple<T...>*使主叫方可以明确的:

template <typename... TListElems, typename... TVectorElems>
void foo(std::tuple<TListElems...>*,
         std::tuple<TVectorElems...>*,
         void (*)(std::list<TListElems>..., std::vector<TVectorElems>...))
{
    // blah blah blah
}

void bar(std::list<int>, std::list<unsigned>, std::vector<float>, std::vector<double>)
{
    // blah blah blah
}

int main()
{
    foo((std::tuple<int, unsigned>*) nullptr,
        (std::tuple<float, double>*) nullptr,
        &bar);
}
Run Code Online (Sandbox Code Playgroud)

Clang愉快地以我期望的方式编译它,而g ++(7.2.1)给出了编译错误:

matching.cpp: In function ‘int main()’:
matching.cpp:20:13: error: no matching function for call to ‘foo(std::tuple<int, unsigned int>*, std::tuple<float, double>*, void (*)(std::list<int>, std::list<unsigned int>, std::vector<float>, std::vector<double>))’
         &bar);
             ^
matching.cpp:6:6: note: candidate: template<class ... TListElems, class ... TVectorElems> void foo(std::tuple<_Tps ...>*, std::tuple<_Elements ...>*, void (*)(std::list<TListElems>..., std::vector<TVectorElems>...))
 void foo(std::tuple<TListElems...>*,
      ^~~
matching.cpp:6:6: note:   template argument deduction/substitution failed:
matching.cpp:20:13: note:   mismatched types ‘std::vector<TVectorElems>’ and ‘std::list<int>’
         &bar);
             ^
Run Code Online (Sandbox Code Playgroud)

main,我希望调用foo推断TListElems为as <int, unsigned>TVectorElemsas <float, double>,导致fn类型void (*)(std::list<int>, std::list<unsigned>, std::vector<float>, std::vector<double>)(当只有一个包或者我手动编写过载时,操作的方式).

§14.8.2.5/ 10是最接近明确阻止该foo示例工作的标准:

[注意:函数参数包只能出现在参数声明列表(8.3.5)的末尾. - 尾注]

std::list<TListElems>...fn似乎将违反本说明,但是这并不完全清楚.

问题是:谁是对的?GCC,Clang还是其他什么?

Bar*_*rry 3

我认为 clang 就在这里。

在 中void (*)(std::list<TListElems>..., std::vector<TVectorElems>...)TListElems...一个非推导的上下文,这TVectorElems...也使得一个非推导的上下文。但是两个参数包都可以从两个元组指针参数中推导出来,并且预计也可以在这里使用该推导结果

我提交了gcc bug 83542