C++11 std::function const 重载歧义
C++11 std::function const overload ambiguity
我在处理一个较大程序的一部分时遇到问题,我说的不明确的内容被 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
}
};
我希望在 bar
中对 ::foo
的调用明确解析为标有 xxx
的 const 版本,而两个编译器都抱怨重载解析是模棱两可:
g++ -std=c++11 -c -Wall amb.cpp
amb.cpp: In member function ‘void Foo::bar() const’:
amb.cpp:18:40: error: call of overloaded ‘foo(Foo::bar() const::<lambda(const Foo&, int)>)’ is ambiguous
this->foo([](const Foo&, int){});
^
amb.cpp:12:10: note: candidate: void Foo::foo(std::function<void(const Foo&, int)>) const
void foo(std::function<void(const Foo&, int)>f) const;
^
amb.cpp:15:10: note: candidate: void Foo::foo(std::function<void(const std::basic_string<char>&, const Foo&)>) const
void foo(std::function<void(const std::string&, const Foo&)>f) const;
^
为什么不清楚我要调用哪个版本?我该如何解决这个问题?
您可以使构造函数采用 std::string
参数 explicit
。这样编译器就无法进行从 std::string
到 Foo
.
的隐式转换
问题是当从 lambda 传递给 std::function
对象(特别是参数类型)时,一些类型信息丢失了。
更具体地说,例如接受 std::function<void(int)>
的函数和另一个接受 std::function<void(double)>
的函数对于接受 int
参数的 void
lambda 被认为是同样好的重载。
例如
#include <functional>
void foo(std::function<void(int)>f);
void foo(std::function<void(double)>f);
void bar() {
foo([](int){});
}
bar
中的调用被认为是不明确的
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);
^
解决方法
一个解决方案是显式创建适当的 std::function
对象:
this->foo(std::function<void(const Foo&, int)>([](const Foo&, int){}));
我在处理一个较大程序的一部分时遇到问题,我说的不明确的内容被 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
}
};
我希望在 bar
中对 ::foo
的调用明确解析为标有 xxx
的 const 版本,而两个编译器都抱怨重载解析是模棱两可:
g++ -std=c++11 -c -Wall amb.cpp
amb.cpp: In member function ‘void Foo::bar() const’:
amb.cpp:18:40: error: call of overloaded ‘foo(Foo::bar() const::<lambda(const Foo&, int)>)’ is ambiguous
this->foo([](const Foo&, int){});
^
amb.cpp:12:10: note: candidate: void Foo::foo(std::function<void(const Foo&, int)>) const
void foo(std::function<void(const Foo&, int)>f) const;
^
amb.cpp:15:10: note: candidate: void Foo::foo(std::function<void(const std::basic_string<char>&, const Foo&)>) const
void foo(std::function<void(const std::string&, const Foo&)>f) const;
^
为什么不清楚我要调用哪个版本?我该如何解决这个问题?
您可以使构造函数采用 std::string
参数 explicit
。这样编译器就无法进行从 std::string
到 Foo
.
问题是当从 lambda 传递给 std::function
对象(特别是参数类型)时,一些类型信息丢失了。
更具体地说,例如接受 std::function<void(int)>
的函数和另一个接受 std::function<void(double)>
的函数对于接受 int
参数的 void
lambda 被认为是同样好的重载。
例如
#include <functional>
void foo(std::function<void(int)>f);
void foo(std::function<void(double)>f);
void bar() {
foo([](int){});
}
bar
中的调用被认为是不明确的
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);
^
解决方法
一个解决方案是显式创建适当的 std::function
对象:
this->foo(std::function<void(const Foo&, int)>([](const Foo&, int){}));