C++11 C++;11标准::函数常量重载模糊

C++11 C++;11标准::函数常量重载模糊,c++11,overloading,std-function,const-correctness,C++11,Overloading,Std Function,Const Correctness,我在一个更大的程序中遇到了一个问题,g++和clang++ #include <functional> #include <string> struct Foo { Foo(int) {} Foo(std::string) {} operator int () const { return 42; } operator std::string () const { return ""; } void foo(std::funct

我在一个更大的程序中遇到了一个问题,
g++
clang++

#include <functional>
#include <string>

struct Foo {
    Foo(int) {}
    Foo(std::string) {}
    operator int () const { return 42; }
    operator std::string () const { return ""; }

    void foo(std::function<void(Foo&, int)>f);
    void foo(std::function<void(const Foo&, int)>f) const; // xxx

    void foo(std::function<void(const std::string&, Foo&)>f);
    void foo(std::function<void(const std::string&, const Foo&)>f) const;

    void bar() const {
        this->foo([](const Foo&, int){}); // xxx
    }
};

为什么不清楚我要调用哪个版本?如何解决此问题?

您可以使构造函数使用
std::string
参数
显式
。这样编译器就不能从
std::string
Foo

进行隐式转换。问题是,当从lambda传递到
std::function
对象(尤其是参数类型)时,某些类型信息丢失

更具体地说,例如,一个接受
std::function
的函数和另一个接受
std::function
的函数对于接受
void
lambda的
int
参数被认为是同样好的重载

例如

#include <functional>

void foo(std::function<void(int)>f);
void foo(std::function<void(double)>f);

void bar() {
    foo([](int){});
}
变通办法 解决方案是显式创建适当的
std::function
对象:

this->foo(std::function<void(const Foo&, int)>([](const Foo&, int){}));
this->foo(std::function([](const-foo&,int){});

查看
std::function
的构造函数约束。两个命名重载都是允许的。两者都产生用户定义的转换,两者都不比另一个好。@KerrekSB:我不太明白。标记的版本具有相同的std::function参数声明,其他版本则没有。为什么这也被认为是用户定义的转换?您的函数参数是lambda表达式,而不是
std::function
类型的表达式。所以您需要一个转换。@6502那么您将继续有一个歧义,除非您可以用其他方法解决它。顺便说一下,我认为隐式转换的需要是一种设计气味,它会使代码更难读和理解。随着我的答案的变化,代码工作了(并且在整个程序中工作)。对C/C++类型进行隐式转换的必要性是必不可少的(基本上是实现一种无类型的值来支持JSON数据,因此隐式/转换是为了使对象更有用)。当然,JSON和C++之间有一种阻抗不匹配,但在这种特殊情况下,我不会称之为气味。你有没有更多的关于这是为什么的信息?我遇到了这个问题,想办法解决这个问题,因为没有太多的信息。”本杰明:对不起,我不是语言律师,我从来没有尝试过实现C++前端。不幸的是,C中的概念被关闭了,因此它们有点“闩上”C++和非常奇怪的对象(例如,每个lambda定义是它自己的唯一类型,即使它有相同的接口)。也许这些缺点是不可避免的,因为语言中的所有其他附加功能。。。
amb2.cpp: In function ‘void bar()’:
amb2.cpp:8:18: error: call of overloaded ‘foo(bar()::<lambda(int)>)’ is ambiguous
     foo([](int){});
                  ^
amb2.cpp:4:6: note: candidate: void foo(std::function<void(int)>)
 void foo(std::function<void(int)>f);
      ^
amb2.cpp:5:6: note: candidate: void foo(std::function<void(double)>)
 void foo(std::function<void(double)>f);
      ^
this->foo(std::function<void(const Foo&, int)>([](const Foo&, int){}));