我坚持修复这个gcc警告:我得到了方法“registerCalBack”的树版本,每个版本都采用了通过std :: function引入的不同“可调用”。根据我声明的各种可调用类型,我可以编译或不编译,gcc发出警告“调用重载registerCallBackxxxxx是不明确的”。
我知道重载可以通过编译器考虑参数而不是返回类型来解决,但在这种情况下我无法理解为什么gcc看到歧义:对我来说,每个TCallBack ...我定义的参数不同,当我改变时返回类型的第三个,它编译...这真的让我很困惑。我想部分问题来自于一些参数实际上是不完整类型的事实,但这是从SDL标头访问它们的方式,所以我将它复制到我在这个线程中提供的示例。
在代码中的注释中,您获得了编译的定义示例以及其他未编译的定义示例。
我希望你们中的一些人比我更了解,现在我不知道在哪里看。提前谢谢了。
这里是要编译的gcc命令行:
-pedantic -W -Wall -Wextra -std=c++2a -Weffc++ -Wfatal-errors -Winit-self -Wnon-virtual-dtor -Winline -Wmissing-declarations -Wunreachable-code -Wshadow -Wswitch-enum -fstack-protector -Wstack-protector -O0
P.
#include <iostream>
#include <functional>
//This is how SDL_Renderer and SDL_Texture are declared in SDL.h, as incomplete type declaration, to make it opaque
//I reproduce it here with other name, to avoid the need to install SDL if you want to test
struct RENDERER;
typedef struct RENDERER RENDERER;
struct TEXTURE;
typedef struct TEXTURE TEXTURE;
//this is stupid, just to make test
struct dumb;
typedef struct dumb dumb;
class ClassUsingCallBacks // an instance of this class will use callbacks
{
public:
typedef std::function < RENDERER* (void) > TCallBack_GetRenderer;
typedef std::function < TEXTURE* (const std::string&) > TCallBack_GetTexture;
//this works:
// typedef std::function < dumb* (void) >
// typedef std::function < dumb* (TEXTURE*) >
// typedef std::function < int (TEXTURE*) >
// typedef std::function < TEXTURE* (TEXTURE*) >
// BUT THIS FAILED TO COMPILE :
// typdef std::function < void (TEXTURE*) >
// typdef std::function < void* (TEXTURE*) >
// typedef std::function < void (const std::string&, int, int, int)
typedef std::function < void (TEXTURE*) > TCallBack_removeTexture;
virtual ~ClassUsingCallBacks() {};
void registerCallBack(TCallBack_GetRenderer cb) {
std::cout << "Register a TCallBack_GetRenderer" << std::endl;
getRenderer = cb;
}
void registerCallBack(TCallBack_GetTexture cb) {
std::cout << "Register a TCallBack_GetTexture" << std::endl;
getTexture = cb;
}
void registerCallBack(TCallBack_removeTexture cb) {
std::cout << "Register a TCallBack_removeTexture" << std::endl;
removeTexture = cb;
}
//to test registered callbacks
void makeCalls(void) {
if (getRenderer) getRenderer();
if (getTexture) getTexture("a name");
//not this one since it's the one we failed to implement :/
// if (removeTexture) removeTexture();
}
protected:
TCallBack_GetRenderer getRenderer {};
TCallBack_GetTexture getTexture {};
TCallBack_removeTexture removeTexture {};
};
class ClassWithCallBacks
{
public:
virtual ~ClassWithCallBacks() {};
RENDERER* getRenderer(void) {
std::cout << "Inside getRenderer" << std::endl;
return nullptr;
}
TEXTURE* getTexture(const std::string& s) {
(void)s;
std::cout << "Inside getTexture" << std::endl;
return nullptr;
}
void removeTexture(TEXTURE* t) {
(void)t;
std::cout << "Inside removeTexture" << std::endl;
}
};
int main(int argc, char **argv)
{
(void)argc;
(void)argv;
std::cout << "entering main" << std::endl;
ClassWithCallBacks calledObject;
ClassUsingCallBacks user;
auto cb_1 = std::bind(&ClassWithCallBacks::getRenderer, calledObject);
user.registerCallBack(cb_1);
auto cb_2 = std::bind(&ClassWithCallBacks::getTexture, calledObject, std::placeholders::_1);
user.registerCallBack(cb_2);
user.makeCalls();
std::cout << "Leaving main" << std::endl;
return 0;
}
std::bind
生成一个可调用的对象,该对象接受任意数量的参数,并简单地丢弃那些不需要转发到绑定的可调用的参数。
std::function<void(Something)>
接受一个返回结果的callable,然后简单地丢弃这个结果。
因此,cb_1
可以被std::function<RENDERER* (void)>
和std::function<void (TEXTURE*)>
接受。它可以采用(并忽略)TEXTURE*
参数,并且该函数可以忽略其返回值。
从根本上说,你在很大程度上依赖于类型擦除,但是希望你正在擦除的类型仍然有助于指导重载解析。就个人而言,我会给三个registerXXX
函数不同的名称,反映他们正在注册的回调类型。没有超载,没问题。