5

当我用 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) { });
}

但是,如果我将重载函数设为 const,它可以很好地编译并调用我没想到的方法!

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

所以,我有两个问题:

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

TIA。

斯科特。:)

4

1 回答 1

4

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

因此,根据 8.5/16:


[...]

— 如果目标类型是(可能是 cv 限定的)类类型:

[...]

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


和 13.3.1.5:


在 8.5 中指定的条件下,作为非类类型对象初始化的一部分,可以调用转换函数将类类型的初始化表达式转换为正在初始化的对象的类型。重载分辨率用于选择要调用的转换函数。假设“cv1 T”是被初始化对象的类型,“cv S”是初始化表达式的类型,其中S是类类型,候选函数选择如下:

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


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

您可以使用以下简单代码检查这一系列转换:

#include <iostream>
#include <iomanip>

int main()
{
    std::cout << std::boolalpha << []{ return 0; } << '\n';
}

输出将是true...

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

所以,你可以这样做:

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

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

于 2012-12-06T02:22:49.887 回答