为什么gcc从这里的回调函数的最后一个参数推断类型?

问题描述 投票:2回答:1

我正在尝试制作一个模板函数,该模板函数使用指向具有任意数量输入的函数的指针,只是它的最后一个输入必须为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;
}

虽然这不是我最终解决方案的选择。我想知道的是为什么它以一种意想不到的方式推断类型,以及我应该如何解决。

c++ templates variadic-functions
1个回答
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...),我看不到一种简单而优雅的方法(无需开发辅助类)。

© www.soinside.com 2019 - 2024. All rights reserved.