我正在尝试编写一个函数,它使用参数包和一些标准匹配规则来获取另一个函数。举个例子:
template <typename... TListElems, typename... TVectorElems>
void goal(void (*fn)(std::list<TListElems>..., std::vector<TVectorElems>...));
为了消除TListElems
和TVectorElems
的歧义,我添加了一些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);
}
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);
^
在main
中,我期待对foo
的调用,将TListElems
推断为<int, unsigned>
,TVectorElems
推导为<float, double>
1}},导致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>...
的{{1}}位似乎会违反此注释,但这并不完全清楚。
问题是:谁是对的? GCC,Clang还是其他什么?
答案 0 :(得分:3)
我认为clang就在这里。
在void (*)(std::list<TListElems>..., std::vector<TVectorElems>...)
中,TListElems...
为a non-deduced context,这使得TVectorElems...
也a non-deduced context。但是两个参数包都是可以从两个元组指针参数中推导出来的,并且它在这里也只能use that deduction result。
我提交了gcc bug 83542。
答案 1 :(得分:2)
您可能会对两种具有非可推导类型的编译器感到高兴:
template <typename T>
struct non_deducible {
using type = T;
};
template <typename T> using non_deducible_t = typename non_deducible<T>::type;
template <typename... TListElems, typename... TVectorElems>
void foo(std::tuple<TListElems...>*,
std::tuple<TVectorElems...>*,
void (*)(non_deducible_t<std::list<TListElems>>...,
non_deducible_t<std::vector<TVectorElems>>...))
{
// blah blah blah
}