如何解决模糊重载函数调用?

Sco*_*ley 5 c++ overloading g++ c++11

当我用gcc-4.6.3或gcc-4.7.2编译这个程序时,编译器给出了一个关于重载调用不明确的错误:

#include <iostream>
#include <functional>

class Scott
{
    public:
        void func(const bool b = true)
        {
            std::cout << "Called func() with a boolean arg" << std::endl;
        }

        void func(std::function<void(void)> f)
#ifdef WITH_CONST
            const
#endif
        {
            std::cout << "Called func() with a std::function arg" << std::endl;
        }
};


int main (int argc, char *argv[])
{
    Scott s;
    s.func([] (void) { });
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我使重载函数const,它编译很好并调用我没想到的方法!

devaus120>> g++ -Wall -std=c++11 -DWITH_CONST wtf.cxx
devaus120>> ./a.out
Called func() with a boolean arg
Run Code Online (Sandbox Code Playgroud)

所以,我有两个问题:

  1. 这是一个编译器错误,当重载方法是const时,这编译?
  2. 如何确保调用正确的重载函数?(需要以某种方式抛出论点?)

TIA.

斯科特.:)

zau*_*ufi 4

其实gcc是正确的!因为lambda不是一个函数,而是一个类类型的闭包对象!真的吗!您甚至可以从它继承:)...甚至可以从不同的 lambda 多次继承...

\n\n

因此,根据 8.5/16:

\n\n
\n\n

[...]

\n\n

\xe2\x80\x94 如果目标类型是(可能是 cv 限定的)类类型:

\n\n

[...]

\n\n

\xe2\x80\x94否则,如果源类型是(可能是 cv 限定的)类类型,则考虑转换函数。枚举了适用的转换函数(13.3.1.5),并通过重载决议选择最好的转换函数(13.3)。调用如此选择的用户定义转换来将初始化表达式转换为正在初始化的对象。如果转换无法完成或不明确,则初始化格式错误。

\n\n
\n\n

和 13.3.1.5:

\n\n
\n\n

在 8.5 中指定的条件下,作为非类类型对象初始化的一部分,可以调用转换函数将类类型的初始值设定项表达式转换为正在初始化的对象的类型。重载决策用于选择要调用的转换函数。假设 \xe2\x80\x9ccv1 T\xe2\x80\x9d 是正在初始化的对象的类型,而 \xe2\x80\x9ccv S\xe2\x80\x9d 是初始化表达式的类型,其中 S 是一个类类型,候选函数选择如下:

\n\n

-- 考虑S及其基类的转换函数。那些未隐藏在 S 中并产生类型 T 或可通过标准转换序列 (13.3.3.1.1) 转换为类型 T 的类型的非显式转换函数是候选函数。对于直接初始化,那些未隐藏在 S 中并产生类型 T 或可以通过限定转换(4.4)转换为类型 T 的类型的显式转换函数也是候选函数。返回 cv 限定类型的转换函数被视为在选择候选函数的过程中生成该类型的 cv 非限定版本。返回 \xe2\x80\x9creference 到 cv2 X\xe2\x80\x9d 的转换函数返回左值或 x值,具体取决于引用类型,类型为 \xe2\x80\x9ccv2 X\xe2\x80\x9d,因此被视为为选择候选函数的过程产生 X。

\n\n
\n\n

所以最后,转换函数的结果是一个函数指针,它将隐式转换为bool...

\n\n

你可以用下面的简单代码来检查这一系列的转换:

\n\n
#include <iostream>\n#include <iomanip>\n\nint main()\n{\n    std::cout << std::boolalpha << []{ return 0; } << '\\n';\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

输出将是true...

\n\n

这里有几种解决方法......您肯定需要一些东西,因为这两个函数在重载解析后都适用。顺便说一句,将const, 添加到第二个签名的签名中,只需排除它,因为您有一个可变实例,Scott并且如果使用修饰符声明它,您将再次收到编译错误const

\n\n

所以,你可以这样做:

\n\n
    \n
  • 显式转换(如评论中所述)...是的,输入很长...
  • \n
  • 声明第二个 foo w/ 模板参数Func。根据您接下来要做什么,这里有几个选项:它可以转换为std::function分配时(如果您想将其存储给某个成员),或者在立即调用的情况下,您甚至会得到一些优化(通过消除转换为std::function)
  • \n
  • 更复杂的方法是声明两个带有模板参数的函数,并根据例如(或检查可调用/函数类型)来关闭std::enable_if其中一个函数std::is_same<bool, T>
  • \n
  • 使用类型分派(是的,再次使用模板化函数)
  • \n
\n\n

...我想这已经足够了:)

\n