我有以下代码:
#include <iostream>
using namespace std;
template <class T>
int get_num(int k) {
return k + 3;
}
float get_num(float k) {
return k + 3;
}
template <class T1, class T2>
void function(T1 (*callback)(T2), T2 arg) {
callback(arg);
}
int main() {
// your code goes here
function(get_num, 3);
return 0;
}
我需要使用int
参数调用get_num()函数。但编译器会收到此错误:
prog.cpp: In function ‘int main()’: prog.cpp:21:21: error: no matching function for call to ‘function(<unresolved overloaded function type>, int)’ function(get_num, 3); ^ prog.cpp:15:6: note: candidate: template<class T1, class T2> void function(T1 (*)(T2), T2) void function(T1 (*callback)(T2), T2 arg) { ^~~~~~~~ prog.cpp:15:6: note: template argument deduction/substitution failed: prog.cpp:21:21: note: couldn't deduce template parameter ‘T1’ function(get_num, 3);
怎么做?
答案 0 :(得分:2)
一个问题是function
的返回类型和参数类型有不同的类型,但实际上两者都是相同的。
这意味着您可以执行类似
的操作template<typename T, typename F = T(T)>
void function(F callback, T arg)
{
callback(arg);
}
模板参数F
只是为了简化回调参数声明。
答案 1 :(得分:2)
template <class T>
前面有int get_num(int k)
。让我们假设它不存在,然后这可行:
有时您无法将函数更改为模板,但需要使用函数指针指向具有多个重载的函数。选择正确重载的方法是指定函数指针的类型(因为对于不同的重载,函数指针的类型不同)。
typedef int (* int_get_num_t)(int);
int main() {
int_get_num_t correct_overload = get_num;
function(correct_overload, 3);
return 0;
}
如果int get_num(int k)
真的应该是一个模板(那么为什么浮动一个不是?)那么你只需选择模板版本:
int_get_num_t correct_overload = get_num<int>;
实际上您可以传递任何类型而不是int
,因为您的模板get_num
总是需要int
并返回int
而不管模板参数。
最后......你实际上不需要get_num
的第二次重载,但你只需要一个模板。在这种情况下,您仍然需要选择正确的模板来获取函数指针:
template <typename T>
T get_num(T k) { return k + 3; }
template <class T1, class T2>
void function(T1 (*callback)(T2), T2 arg) {
callback(arg);
}
int main() {
int_get_num_t correct_overload = get_num<int>;
function(correct_overload, 3);
return 0;
}
答案 2 :(得分:2)
这是使用 C ++仿函数的那个。
#include <iostream>
using namespace std;
template<class T>
struct get_num : public std::unary_function<T,T>
{
T operator()(const T& k) {
return k+3;
}
};
template< class T1, class T2 >
void function( T1 fun, T2 arg)
{
fun(arg);
cout << fun(arg) << endl;
}
int main()
{
function(get_num<int>(), 3);
return 0;
}
答案 3 :(得分:2)
从template <class T>
移除int get_num(int)
以获得正常的过载设置后,您可以使用Some programmer dude’s answer。
在这个答案中,我想详细说明如何仍然使用基于函数指针的参数。
如果您将参数切换为function
至少gcc is able to deduce it:
template <typename T, typename U>
void function2(T arg, U(*callback)(T)) {
callback(arg);
}
当你在那里使用U
时, clang不喜欢它,所以如果你的返回类型总是与你的参数相同,you can use T
twice:
template <typename T>
void function2(T arg, T(*callback)(T)) {
callback(arg);
}
要解决一般情况下的错误消息中的歧义,您还可以使用static_cast
do the overload resolution manually:
function(static_cast<float(*)(float)>(&get_num), 3.0f);
function(static_cast<int(*)(int)>(&get_num), 3);
答案 4 :(得分:1)
您必须指定功能类型
#include <iostream>
#include <string>
int get_num(int k) {
return k + 3;
}
float get_num(float k) {
return k + 3;
}
std::string get_num (double a)
{
return "this is a string " + std::to_string(a);
}
template <class T1, class T2>
using callback = T1(*)(T2);
template <class T1, class T2>
void function(callback<T1, T2> function, T2 arg) {
std:: cout << function(arg) << std::endl;
}
int main() {
// your code goes here
function<int, int>(get_num, 3);
function<std::string, double>(get_num, 3);
system("pause");
return 0;
}
为什么有两个不同的模板参数? - OP的问题不是关于优化,而是关于
因此,这是解决特定错误的众多实现之一。
答案 5 :(得分:1)
以下代码可以使用:
Private Sub datagridview1_SelectionChanged(sender As Object, e As EventArgs) Handles datagridview1.SelectionChanged
datagridview1.ClearSelection()
End Sub
您收到编译错误的原因是,如果您只使用#include <iostream>
using namespace std;
template<typename T>
int get_num(int k) {
return k + 3;
}
float get_num(float k) {
return k + 3;
}
template<typename T1, typename T2> // Maybe here you want the `typename`, not the `class`
void f(T1 (*callback)(T2), T2 arg) {
callback(arg);
}
int main() {
// your code goes here
f(get_num<int>, 3); // The key point is here!
return 0;
}
,则编译器无法推断出类型T
,因为所有参数都不属于get_num
类型。
答案 6 :(得分:0)
我允许自己简化一下你的代码。这应该可以正常工作:
#include <iostream>
using namespace std;
template <class T>
T get_num(T k) {
return k + 3;
}
template <class T1, class T2>
void function(T1 callback, T2 arg) {
callback(arg);
}
int main() {
function(get_num<int>, 3);
return 0;
}
答案 7 :(得分:0)
我想提供一个稍有不同的解决方案。 我在代码中解释它,使它更有助于阅读和理解:
// create a helper class,
// which collects all callable classes to build one callable object later
template<class... Ts> struct funcs : Ts... { using Ts::operator()...; };
template<class... Ts> funcs(Ts...) -> funcs<Ts...>;
// instead of free functions, build objects with methods
// and use operator() instead of function names.
// this makes it easier to "understand" that this will be an callable object
struct Func1
{
int operator()(int k) {
return k + 3;
}
};
struct Func2
{
float operator()(float k) {
return k + 3;
}
};
// adapt your code to this:
template <class T1, class T2>
auto function(T1 callback, T2 arg) {
return callback(arg);
}
// and finaly you can use it this way, also with return types
// the central hack is:
// funcs{ Func1(), Func2() }
// this will generate a callable object with all the overloads
// from the inserted callable objects
int main() {
// your code goes here
std::cout << function(funcs{ Func1(), Func2() }, 3) << std::endl;
std::cout << function(funcs{ Func1(), Func2() }, (float)7.999) << std::endl;
return 0;
}