在C ++中解析函数/方法/模板名称的偏好是什么?

时间:2010-02-23 16:19:34

标签: c++ templates argument-dependent-lookup

如果有多种可能性,C ++编译器如何决定调用哪个函数/方法? 在我的具体情况下,我有C ++运行时的标准自由函数,我也有一个模板化的免费变体,如下所示:

// The definitions of the C++ Run Time Library (from memory.h)
extern malloc(size_t s);
extern void free(void *p);

// Our own memory management functions
extern void *OurMalloc(size_t s);
extern void OurFree(void *p);

// Own variants to overrule malloc and free (instead of using #define)
template<typename T>
void *malloc(T t)
{
return OurMalloc(t);
}

template<typename T>
void free(T *t)
{
OurFree(t);
}

我使用以下代码对此进行了测试:

void main(void)
{
void *p = malloc(10);
free(p);
}

如果我编译并运行它,似乎对malloc的调用被模板化变体正确替换。到目前为止,非常好。

但是,对free的调用不会被模板化变量替换,并且仍会调用标准C ++函数。

C ++编译器使用哪些规则来决定哪个变体优先? 这与Koenig查找规则有关吗?

注意:我尝试了这种替代方法,因为使用#define无法解决问题(请参阅问题How to use C macro's (#define) to alter calls but not prototypes)。

4 个答案:

答案 0 :(得分:8)

一般来说,过载分辨率非常复杂。

在您的情况下,这很容易:如果存在完全匹配,则不考虑函数模板。免费是这种情况(标准free取一个void *),对于malloc它不是(标准malloc接受size_t,你传递一个int而size_t不能是int的typedef - size_t是unsigned )。如果使用void *以外的类型调用free,则应该实例化模板。

运行:

#include <iostream>

void* ml(size_t s)
{
    std::cout << "ml(size_t)\n";
}

void fr(void *p)
{
    std::cout << "fr(void*)\n";
}

template<typename T>
void* ml(T t)
{
    std::cout << "ml<" << typeid(T).name() << ">(T)\n";
}

template<typename T>
void fr(T *t)
{
    std::cout << "fr<" << typeid(T).name() << ">(T*)\n";
}

int main()
{
    void* p1 = ml((size_t)10);
    fr(p1);
    int* p2 = (int*)ml(10);
    fr(p2);
    return 0;
}

我得到了

ml(size_t)
fr(void*)
ml<i>(T)
fr<i>(T*)

而我正在返回typeid(int).name()

答案 1 :(得分:3)

对于您关于mallocfree的特定问题,问题在于您致电malloc

void *p = malloc(10);

参数10的类型为int,而运行时malloc()的签名则调用unsigned参数。由于没有完全匹配,编译器更喜欢模板malloc,它可以创建完全匹配。

致电时:

free(p);

p的类型是void*,它与free()的运行时签名完全匹配,因此编译器不会使用模板free

答案 2 :(得分:2)

使用此技术无法“替换”标准malloc。其他答案已经解释过,因为您在malloc调用中使用 signed 值作为参数,所以您的模板化版本恰好“胜过”标准版本,因为标准版本需要无符号参数。

为了更好地说明这一点,我只想补充一点,如果您在unsigned int电话中提供unsigned longmalloc参数

void *p1 = malloc(10u);
void *p2 = malloc(10ul);

并且您会注意到在其中一个调用中,malloc的模板化版本也不再“工作”,而是调用标准版本,因为它更适合参数(提供您平台size_t上的内容定义为unsigned intunsigned long

答案 3 :(得分:0)

没有回答你提出的问题,但是你似乎想要做的事情:

如果它在您的系统上可用,您可以使用LD_PRELOAD预加载您构建的具有malloc和free版本的.so库。然后肯定会调用它们而不是标准版本。