将普通成员变量转换为静态成员变量会导致问题。

3
我曾经拥有一个普通的成员变量,在构造函数中初始化如下:
ResourceSaveFunctions[OBJECTS_IDENT] = NULL;
ResourceSaveFunctions[SPRITES_IDENT] = &GMProject::SaveSprite;
ResourceSaveFunctions[SOUNDS_IDENT] = &GMProject::SaveSound;
ResourceSaveFunctions[BACKGROUNDS_IDENT] = &GMProject::SaveBackground;
ResourceSaveFunctions[PATHS_IDENT] = NULL;
ResourceSaveFunctions[SCRIPTS_IDENT] = NULL;
ResourceSaveFunctions[FONTS_IDENT] = NULL;
ResourceSaveFunctions[TIMELINES_IDENT] = NULL;
ResourceSaveFunctions[ROOMS_IDENT] = NULL;
ResourceSaveFunctions["extension"] = &GMProject::SaveExtension;
ResourceSaveFunctions[INCLUDES_IDENT] = NULL;
ResourceSaveFunctions[TRIGGERS_IDENT] = NULL;

变量是一个具有字符串键和成员函数指针的映射。这个方案完全没有问题。然而,我认为这个映射应该是静态的(?) - 映射的原因只是为了在读取文件期间确定程序应该做什么。- NULL表示"不执行任何特殊操作"。
所以我将其更改为以下内容:
std::map<std::string, GMProject::GMProjectMemFn> GMProject::ResourceSaveFunctions_INIT() {
    std::map<std::string, GMProjectMemFn> tmp;
    tmp.insert(std::make_pair(OBJECTS_IDENT,NULL));
    tmp.insert(std::make_pair(SPRITES_IDENT, &GMProject::SaveSprite));
    tmp.insert(std::make_pair(SOUNDS_IDENT, &GMProject::SaveSound));
    tmp.insert(std::make_pair(BACKGROUNDS_IDENT, &GMProject::SaveBackground));
    tmp.insert(std::make_pair(PATHS_IDENT, NULL));
    tmp.insert(std::make_pair(SCRIPTS_IDENT, NULL));
    tmp.insert(std::make_pair(FONTS_IDENT, NULL));
    tmp.insert(std::make_pair(TIMELINES_IDENT, NULL));
    tmp.insert(std::make_pair(ROOMS_IDENT, NULL));
    tmp.insert(std::make_pair("extension", &GMProject::SaveExtension));
    tmp.insert(std::make_pair(INCLUDES_IDENT, NULL));
    tmp.insert(std::make_pair(TRIGGERS_IDENT, NULL));
    return tmp;
}
const std::map<std::string, GMProject::GMProjectMemFn> GMProject::ResourceSaveFunctions(GMProject::ResourceSaveFunctions_INIT());

这些东西在头文件中声明:

static const std::map<std::string, GMProjectMemFn> ResourceSaveFunctions;
static std::map<std::string, GMProjectMemFn> ResourceSaveFunctions_INIT();

现在编译突然出现很多错误。
1>c:\program files\microsoft visual studio 10.0\vc\include\utility(163): error C2440: 'initializing' : cannot convert from 'int' to 'GMProject::GMProjectMemFn '
这是关于NULL的转换。但这不应该是可能的吗?为什么这不可能(前一个方法中却可以)? 我是否应该在此处使用显式转换?
编辑: GMProjectMemFn定义如下:
typedef void (GMProject::*GMProjectMemFn)(const pTree&) const; 

pTree 是一个容器。


GMProjectMemFn的定义是什么? - Constantinius
你自己实现了虚拟表吗?我不清楚你的成员函数指针大地图是用来干什么的...看起来像是C程序中的东西。 - John Zwinck
@Kerrek_SB “部分地” - 使用Visual Studio 2010 - 但是我无法使用初始化列表。 - paul23
@JohnZwinck 这个用于类似“xml文件”的东西 - 通常在保存时可以使用标准方法 - 它包括读取包含文件位置的xml值,然后复制该文件。但是由于我无法控制xml文件的格式,在某些特定情况下需要发生一些额外的事情。对于这些情况,我编写了一个单独的函数。 - paul23
2个回答

1

std::make_pair 创建一个 pair<T1, T2>,其中类型 T1T2 从参数的类型中隐式推导出来。 NULL 扩展为 0(或 0L),所以在您的情况下,make_pair 返回一个 pair<string, int>(或 pair<string, long>)。

然后,您尝试将该 pair<string, int> 传递给 map<string, GMProject::GMProjectMemFn>::insert(),但这需要一个 pair<string, GMProjectMemFn>

std::pair 具有通用的复制构造函数,它将尝试隐式转换每个成员的 pair:

template <class U, class V>
    pair (const pair<U,V> &p) : first(p.first), second(p.second) { }

但在您的情况下,这需要将 const int& 转换为指针,这是不允许的。

在您原来的情况下,您直接将 NULL 转换为指针,这是明确定义的。

显式地为您的 pair 进行类型设置应该可以解决这个问题:

tmp.insert(std::pair<std::string, GMProject::GMProjectMemFn>(TIMELINES_IDENT, NULL));

1
但是std::pair不是有一个非“explicit”的广义拷贝构造函数,可以接受任意类型的std::pair并执行逐成员转换吗?所以只要int可以转换为GMProjectMemFn,那么pair<string,int>确实应该可以转换为pair<string,GMProjectMemFn> - Christian Rau
是的,你说得完全正确。真正的问题在于 int const& 不能隐式转换为指针。我会更正我的回答。感谢你指出这一点! - atkins

0

啊。NULL 可能只被定义为字面量 0,make_pair 推断它为整数,而 pair<int,int> 无法转换为 pair<int,GMProjectMemFn>。通过 operator[] 赋值可以工作,因为(我猜)从 0 到 GMProjectMemFn 的隐式转换。

所以,尝试编写 make_pair(PATHS_IDENT, (GMProjectMemFn)0)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接