我正在尝试制作一个模板函数,该模板函数使用指向具有任意数量输入的函数的指针,只是它的最后一个输入必须为int。然后,模板函数应使用提供的参数和最后一个参数五个来调用此函数。该代码将使其变得清晰:
#include <iostream>
template<class A, class ... B>
void passFive(A (*f)(B ..., int n), B ... x) {
f(x ..., 5);
}
void printStrAndInt(const char *s, int n) {
std::cout << s << " " << n << "\n";
}
int main() {
passFive(&printStrAndInt, "pineapple");
return 0;
}
但是,gcc不喜欢这样,给我一个错误和注释:
test.cpp: In function ‘int main()’:
test.cpp:14:39: error: no matching function for call to ‘passFive(void (*)(const char*, int), const char [10])’
passFive(&printStrAndInt, "pineapple");
^
test.cpp:4:6: note: candidate: template<class A, class ... B> void passFive(A (*)(B ..., int), B ...)
void passFive(A (*f)(B ..., int n), B ... x) {
^~~~~~~~
test.cpp:4:6: note: template argument deduction/substitution failed:
test.cpp:14:39: note: mismatched types ‘int’ and ‘const char*’
passFive(&printStrAndInt, "pineapple");
因此,它一次将B的类型作为const char *(如预期的那样)进行推断,还一次将其作为printStrAndInt的第二个参数进行推断(我敢肯定,因为它与int之外的其他数据类型相同)。顺便说一句,如果我将int移到前面,它就可以正常工作:
#include <iostream>
template<class A, class ... B>
void passFive(A (*f)(int n, B ...), B ... x) {
f(5, x ...);
}
void printStrAndInt(int n, const char *s) {
std::cout << s << " " << n << "\n";
}
int main() {
passFive(&printStrAndInt, "pineapple");
return 0;
}
虽然这不是我最终解决方案的选择。我想知道的是为什么它以一种意想不到的方式推断类型,以及我应该如何解决。
问题:只有在最后一个位置时,才可以推导模板参数的可变列表。
还算一下,如果不在最后位置,则被推为空。
所以,来自
template<class A, class ... B>
void passFive(A (*f)(B ..., int n), B ... x) {
f(x ..., 5);
}
和通话
passFive(&printStrAndInt, "pineapple");
可变参数B...
列表必须从f
签名推导出为Empy(B...
不在最后一个位置,后跟int
)和char const *
(或者也许是char const [10]
) ]。
为避免这种情况,您可以推断出两个不同的列表,并强加(SFINAE或"pineapple"
)第二个可变参数列表作为第一个可变参数列表,并添加static_assert()
。
我的意思是(以SFINAE的方式表示为] >>
int
不是一个完美的解决方案:就像您的原始代码一样,如果
template <typename A, typename ... Bs, typename ... Cs> std::enable_if_t<std::is_same_v<std::tuple<Bs...>, std::tuple<Cs..., int>>> passFive(A (*f)(Bs ...), Cs ... x) { f(x ..., 5); }
函数等待(例如)一个f
,并且在long
自变量中传递一个x...
,则是一个问题。
最好检查int
类型(加上Cs...
)是否不相等,但可以转换为int
。但是(鉴于最后的Bs...
),我看不到一种简单而优雅的方法(无需开发辅助类)。