这是一个简单的示例程序:
using fn_string = function<void(const string&)>;
using fn_optional_string = function<void(const optional<string>&)>;
void foo(fn_string) { cout << "string" << endl; }
void foo(fn_optional_string) { cout << "optional string" << endl; }
int main()
{
foo([&](const string&){ });
foo([&](const optional<string>&){ }); // <-- ambiguous
return 0;
}
它有 2 个重载 foo()
-- 一个使用 string
的函数参数和另一个 optional<string>
.
为什么第二次调用 foo()
模棱两可?
有没有简单的方法来修复它?没有 Actor ?
更新
以上是我试图解决的以下现实世界问题的过度简化示例,即:
using delegate = variant<
function<void()>,
function<void(const string&)>,
function<void(const optional<string>&)>
>;
struct foo
{
void add_delegate(delegate fn) { fns.push_back(std::move(fn)); }
vector<delegate> fns;
};
int main()
{
foo bar;
bar.add_delegate([&](){ });
bar.add_delegate([&](const string&){ });
bar.add_delegate([&](const optional<string>&){ }); // ERROR
return 0;
}
最后一次调用 add_delegate
无法编译,因为它无法在 function<void(const string&)>
之间做出决定和 function<void(const optional<string>&)>
.
我的理解是这个问题与重载决议有关(因此我的原始示例)。我应该对 add_delegate
做哪些更改?允许它接受所有 3 个版本的 lambda 表达式?
完整示例可以在 Coliru 上找到.
最佳答案
lambda 不是 std::function<>
. std::function<R(Args...)>
是一种类型删除值类型,可以存储与 R(Args...)
调用兼容的任何可复制对象.
在上面的一个例子中,R
是void
(对于 std::function
表示“我不在乎它返回什么”),而 Args...
是 std::string
。如果您可以使用 std::string
右值调用可调用对象,则可调用对象与此调用兼容。
std::optional<std::string>
都是如此和 std::string
.
“完全匹配”没有特殊的重载——重要的是调用兼容与否。
有几种方法可以解决这个问题。
template<std::size_t N>
struct overload_order : overload_order<N-1> {};
template<>
struct overload_order<0> {};
namespace details {
void foo(overload_order<1>, fn_string) { cout << "string" << endl; }
void foo(overload_order<0>, fn_optional_string) { cout << "optional string" << endl; }
}
template<class F>
void foo(F&& f) {
foo( overload_order<!std::is_same<std::decay_t<F>, fn_optional_string>{}>{}, std::forward<F>(f) );
}
现在我们首先尝试 fn_string
一个,只有当失败时,我们才会尝试 fn_optional_string
, 除非参数已经是 fn_optional_string
,在这种情况下,我们直接分派(dispatch)到该重载。
关于c++ - 使用带有 std::optional 参数的 std::function 重载歧义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49567521/