如何使用可变参数解析工作函数重载?

问题描述:

#define FALSE 0 
#define TRUE 1 

#define IDS_MYSTR 123 

void FnVariadic(const long nIDS, ...) 
{ 
    std::cout << "WITHOUT option IDS" << std::endl; 
} 

void FnVariadic(const bool bOption, const long nIDS, ...) 
{ 
    std::cout << "WITH option IDS" << std::endl; 
} 

void FnVariadic(const char *pStr, ...) 
{ 
    std::cout << "WITHOUT option STR" << std::endl; 
} 

void FnVariadic(const bool bOption, const char *pStr, ...) 
{ 
    std::cout << "WITH option STR" << std::endl; 
} 


int main() 
{ 
    FnVariadic(FALSE, IDS_MYSTR, "abc"); 
    //FnVariadic(IDS_MYSTR, FALSE, "abc"); //??? 
    FnVariadic(TRUE, IDS_MYSTR, "abc"); 
    FnVariadic(IDS_MYSTR, TRUE, "abc"); //??? 

    FnVariadic(FALSE, "abc%s", "abc"); 
    //FnVariadic("abc%d%s", FALSE, "abc"); 
    FnVariadic(TRUE, "abc%s", "abc"); 
    //FnVariadic("abc%d%s", TRUE, "abc"); 

    system("pause"); 

    return 0; 
} 

有人可以解释一下这里怎么工作funtion超载解析? 令人惊讶的是,如何使用可变参数解析工作函数重载?

//FnVariadic(IDS_MYSTR, FALSE, "abc"); //??? 
    FnVariadic(IDS_MYSTR, TRUE, "abc"); //??? 

第二个编译但不是第一个编译。

(注释行的意思是不编译)

我使用VS2017,似乎;

首先3个电话使用void FnVariadic(const bool bOption, const long nIDS, ...)和最后2个呼叫使用void FnVariadic(const bool bOption, const char *pStr, ...)

它也intresting那里。我期望的是应该调用没有布尔参数的重载。

+3

您的问题FALSE是#define'd,因为0等于空指针常量,因此解析在long和const char *重载之间是不明确的。这种情况只存在于字面常量0,这就是为什么设计nullptr的原因(但正如你所看到的,问题仍然存在于语言中)。 – Shaggi

+0

为什么你需要用宏定义'true'和'false'?这些布尔常量是在语言时代之前建立起来的。 – AndyG

+0

@AndyG我们正在使用mfc/atl。这些代码已被写入,没有布尔真/假。这些定义已被使用。但我想了解超负荷解决。不寻找解决方案。 –

在重载分辨率中,省略号是最后的手段,如果有更好的匹配,则函数调用将被解析为匹配。你的函数调用(非注释)都包含一个整数字面量作为第一个参数。而且,由于您的宏,当更换是转换到bool所有可行的候选人,你有两个候选人

void FnVariadic(const bool bOption, const long nIDS, ...) 
void FnVariadic(const bool bOption, const char *pStr, ...) 

然后在前三您提供整型常量作为第二个参数。因此,上述两者之间的第一次重载被称为。在最后2中,您提供了字符串文字(可减少到const char*),因此第二次重载被称为上述两者之间。


至于为何注释行不进行编译

// FnVariadic(IDS_MYSTR, FALSE, "abc"); //??? 

这不会编译,因为第二个参数是模糊的,一个0具有特殊的意义不幸的是,它可以解决这两个一const char*以及作为const long

// FnVariadic("abc%d%s", FALSE, "abc"); 

同样为这一项,FALSE是模糊

// FnVariadic("abc%d%s", TRUE, "abc"); 

这里转化为bool"abc%d%s"和​​到椭圆匹配具有相同的优先级,并且因此它是不明确的。


供您参考,它几乎总是最好使用对C风格variadics编译时可变参数模板。

+0

是否可以停用这种隐式的0 - > ptr转换?我的意思是可以防止0作为ptr代表?用编译器选项也许? –

+1

@YusufR.Karagöz号GCC对此有警告,但在许多情况下,语言没有进行这种转换就会中断。如果您对解决方案感兴趣,那么重构代码非常容易,因此它可以正常工作(例如,使用SFINAE)。 – Shaggi

正如@Shaggi已经指出的那样。按照标准,

在引入nullptr之前,将零(0)用作 空指针的标记。例如:

int* x = 0; // x gets the value nullptr 

无对象与地址0分配,并且0(全零位 图案)是nullptr最常见的代表。零(0)是一个 int。但是,标准的转换(§10.5.2.3)允许0使用 作为指针或指针到成员类型

FnVariadic(IDS_MYSTR, FALSE, "abc"); 
         ^~~~const char * OR const long. This is ambiguous. 

的常数作为你有两个

void FnVariadic(const bool bOption, const long nIDS, ...) 
void FnVariadic(const bool bOption, const char *pStr, ...)