当我用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) { });
}
但是,如果我将重载函数设为常量,则编译为精细&amp;调用我没想到的方法!
devaus120>> g++ -Wall -std=c++11 -DWITH_CONST wtf.cxx
devaus120>> ./a.out
Called func() with a boolean arg
所以,我有两个问题:
TIA。
斯科特。 :)
答案 0 :(得分: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和yield类型T中的非显式转换函数或可通过标准转换序列(13.3.3.1.1)转换为类型T的类型是候选函数。 For直接初始化,那些未隐藏在S和yield类型T中的显式转换函数,或者可以通过限定转换(4.4)转换为类型T的类型也是候选函数。返回cv限定类型的转换函数被认为是为此选择候选函数的过程产生该类型的cv非限定版本。返回“引用cv2 X”的转换函数返回lvalues或xvalues,具体取决于引用的类型,类型为“cv2 X”,因此被认为在此选择候选函数的过程中产生X.
所以最后,转换函数的结果是一个函数指针,它会隐式转换为bool
...
您可以使用以下简单代码检查此系列转换:
#include <iostream>
#include <iomanip>
int main()
{
std::cout << std::boolalpha << []{ return 0; } << '\n';
}
输出将为true
...
以下是解决方法的几种方法......你肯定需要一些东西,因为这两个函数在重载解析后都是合适的。顺便说一句,将const
添加到第二个签名,只是排除它,因为你有一个Scott
的可变实例,如果声明它{/ 1}你又会得到编译错误}修饰符。
所以,你可以这样做:
const
。根据您将要执行的操作,这里有几个选项:它可以在分配时转换为Func
(如果您想将其存储到某个成员),或者在立即通话的情况下您甚至可以获得一些优化(通过消除转换为std::function
)std::function
将其中一个 OFF 取决于std::enable_if
,例如(或检查callable /功能类型)......我想这已经足够了:)