在 C++ 中如何传递函数指针并在函数中进行比较?
How can you pass a function pointer and compare it in a function in C++?
出于测试原因,我有一定数量的方法,它们在 C++ 中的签名如下所示:
dvec3 (*)(dvec3, dvec3, double)
我把它们放在一个向量中,如下所示:
vector<dvec3 (*)(dvec3, dvec3, double)> methods = {lerp, plerp, splerp, ilerp};
想法是创建一个函数,该函数接受函数指针和 returns 一个字符串来标识当前正在使用的函数(即我想打印出上面 4 个函数中的哪个函数是正在使用)
为此我尝试将方法写成如下(我故意省略了大部分情况):
string inline erpToString(dvec3 (*f)(dvec3, dvec3, double))
{
if (f==lerp)
{
return "Lerp";
}
}
但是上面的代码没有编译,错误消息指出这是一个转换错误。我做错了什么?
编辑:
编译器消息:
/home/kronos/Desktop/OpenGL-Template/source/Rendering/rendering.cpp: In function ‘std::__cxx11::string erpToString(glm::dvec3* (*)(glm::dvec3, glm::dvec3, double))’:
/home/kronos/Desktop/OpenGL-Template/source/Rendering/rendering.cpp:1362:7: error: invalid operands of types ‘glm::dvec3* (*)(glm::dvec3, glm::dvec3, double) {aka glm::tvec3<double, (glm::precision)0>* (*)(glm::tvec3<double, (glm::precision)0>, glm::tvec3<double, (glm::precision)0>, double)}’ and ‘<unresolved overloaded function type>’ to binary ‘operator==’
if (f==lerp)
~^~~~~~
make[2]: *** [CMakeFiles/voxel-world.dir/build.make:111: CMakeFiles/voxel-world.dir/source/Rendering/rendering.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:68: CMakeFiles/voxel-world.dir/all] Error 2
编辑:
我制作了具有相同逻辑的最小可能文件,但它不会重现错误:
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <string>
using namespace std;
using namespace glm;
dvec3 lerp(dvec3 p1, dvec3 p2, double t)
{
return (1-t)*p1+t*p2;
}
string inline erpToString(dvec3 (*f)(dvec3, dvec3, double))
{
if (f==lerp)
{
return "Lerp";
}
}
int main()
{
}
试用代码表明其他方法(ilerp 和公司)确实有效。所以我似乎有一个命名空间冲突(使用命名空间是的)。 SInce GLM 定义了一个 lerp 函数,但我需要使用的是我定义的那个。有人有建议吗?
您可以使用 using
或 typedef
来简化所有事情。代码对我有用
int a(float x, float y, double z)
{
return int(x + y + z);
}
int b(float x, float y, double z)
{
return int(x - y - z);
}
using fdef = int(*)(float, float, double); // or typedef int (*fdef)(float, float, double);
std::vector<fdef> v{a, b};
if (v[0] == a)
std::cout << "qqq\n";
关键是‘<unresolved overloaded function type>’
特别是,您有两个 lerp
函数。这通常是允许的。在大多数情况下,C++ 会确定您想要哪一个。例如,当您调用 lerp(arg1,arg2, arg3)
时,C++ 将使用这三个参数进行重载解析。但是在f==lerp
中,重载决议没有三个参数。这就是为什么 C++ 说 "unresolved overload".
解决方案是将lerp
转换为f的类型:if (f==static_cast<decltype(f)>(&lerp))
。用于重载决议的三个参数是 f
.
问题是因为 GLM 也定义了一个 lerp 函数,因此编译器无法选择我指的是哪个函数。
按照评论中的建议,解决方案是将我的函数从 lerp
重命名为 mlerp
我想这是一个很好的例子,说明为什么使用命名空间不是一个好主意。
这不是对如何修复错误的回答,而是对您尝试提供所用方法名称的回答。
我建议你使用std::unordered_map来区分不同的功能。
std::unordered_map<void*, const char*> funcmap{4};
union cast_fptr {
dvec3 (*)(dvec3, dvec3, double) fptr;
void *void_ptr;
};
#define MAP_VAL(FUNC_NAME) std::pair<void*, const char*>{cast_fptr{.fptr = &FUNC_NAME}.void_ptr, #FUNC_NAME}
funcmap.insert({MAP_VAL(lerp), MAP_VAL(plerp), MAP_VAL(splerp), MAP_VAL(ilerp)});
#undef MAP_VAL
inline const char* erpToString(dvec3 (*f)(dvec3, dvec3, double)) noexcept {
return funcmap[f];
}
出于测试原因,我有一定数量的方法,它们在 C++ 中的签名如下所示:
dvec3 (*)(dvec3, dvec3, double)
我把它们放在一个向量中,如下所示:
vector<dvec3 (*)(dvec3, dvec3, double)> methods = {lerp, plerp, splerp, ilerp};
想法是创建一个函数,该函数接受函数指针和 returns 一个字符串来标识当前正在使用的函数(即我想打印出上面 4 个函数中的哪个函数是正在使用)
为此我尝试将方法写成如下(我故意省略了大部分情况):
string inline erpToString(dvec3 (*f)(dvec3, dvec3, double))
{
if (f==lerp)
{
return "Lerp";
}
}
但是上面的代码没有编译,错误消息指出这是一个转换错误。我做错了什么?
编辑:
编译器消息:
/home/kronos/Desktop/OpenGL-Template/source/Rendering/rendering.cpp: In function ‘std::__cxx11::string erpToString(glm::dvec3* (*)(glm::dvec3, glm::dvec3, double))’:
/home/kronos/Desktop/OpenGL-Template/source/Rendering/rendering.cpp:1362:7: error: invalid operands of types ‘glm::dvec3* (*)(glm::dvec3, glm::dvec3, double) {aka glm::tvec3<double, (glm::precision)0>* (*)(glm::tvec3<double, (glm::precision)0>, glm::tvec3<double, (glm::precision)0>, double)}’ and ‘<unresolved overloaded function type>’ to binary ‘operator==’
if (f==lerp)
~^~~~~~
make[2]: *** [CMakeFiles/voxel-world.dir/build.make:111: CMakeFiles/voxel-world.dir/source/Rendering/rendering.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:68: CMakeFiles/voxel-world.dir/all] Error 2
编辑:
我制作了具有相同逻辑的最小可能文件,但它不会重现错误:
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <string>
using namespace std;
using namespace glm;
dvec3 lerp(dvec3 p1, dvec3 p2, double t)
{
return (1-t)*p1+t*p2;
}
string inline erpToString(dvec3 (*f)(dvec3, dvec3, double))
{
if (f==lerp)
{
return "Lerp";
}
}
int main()
{
}
试用代码表明其他方法(ilerp 和公司)确实有效。所以我似乎有一个命名空间冲突(使用命名空间是的)。 SInce GLM 定义了一个 lerp 函数,但我需要使用的是我定义的那个。有人有建议吗?
您可以使用 using
或 typedef
来简化所有事情。代码对我有用
int a(float x, float y, double z)
{
return int(x + y + z);
}
int b(float x, float y, double z)
{
return int(x - y - z);
}
using fdef = int(*)(float, float, double); // or typedef int (*fdef)(float, float, double);
std::vector<fdef> v{a, b};
if (v[0] == a)
std::cout << "qqq\n";
关键是‘<unresolved overloaded function type>’
特别是,您有两个 lerp
函数。这通常是允许的。在大多数情况下,C++ 会确定您想要哪一个。例如,当您调用 lerp(arg1,arg2, arg3)
时,C++ 将使用这三个参数进行重载解析。但是在f==lerp
中,重载决议没有三个参数。这就是为什么 C++ 说 "unresolved overload".
解决方案是将lerp
转换为f的类型:if (f==static_cast<decltype(f)>(&lerp))
。用于重载决议的三个参数是 f
.
问题是因为 GLM 也定义了一个 lerp 函数,因此编译器无法选择我指的是哪个函数。
按照评论中的建议,解决方案是将我的函数从 lerp
重命名为 mlerp
我想这是一个很好的例子,说明为什么使用命名空间不是一个好主意。
这不是对如何修复错误的回答,而是对您尝试提供所用方法名称的回答。
我建议你使用std::unordered_map来区分不同的功能。
std::unordered_map<void*, const char*> funcmap{4};
union cast_fptr {
dvec3 (*)(dvec3, dvec3, double) fptr;
void *void_ptr;
};
#define MAP_VAL(FUNC_NAME) std::pair<void*, const char*>{cast_fptr{.fptr = &FUNC_NAME}.void_ptr, #FUNC_NAME}
funcmap.insert({MAP_VAL(lerp), MAP_VAL(plerp), MAP_VAL(splerp), MAP_VAL(ilerp)});
#undef MAP_VAL
inline const char* erpToString(dvec3 (*f)(dvec3, dvec3, double)) noexcept {
return funcmap[f];
}