[英]Why is this call of overloaded function ambiguous?
为什么这个构造函数调用不明确?
#include <functional>
class A {
std::function<int(void)> f_;
std::function<float(void)> g_;
public:
A(std::function<int(void)> f) { f_ = f; }
A(std::function<float(void)> g) { g_ = g; }
~A() {}
};
int main()
{
A a([](){ return (int)1; });
return 0;
}
注意类型转换。
有没有办法告诉编译器使用哪个构造函数重载?
因为您传递的内容与类型不匹配所以我们进入转换序列以查找要使用的重载。 可以从返回int的lambda对象隐式创建两个版本的函数。 因此编译器无法决定选择创建哪个; 虽然看起来很直观,C ++中的规则不允许这样做。
编辑:
写下袖口,但我认为这可以做到这一点:
template < typename Fun >
typename std::enable_if<std::is_same<typename std::result_of<Fun()>::type, int>::value>::type f(Fun f) ...
template < typename Fun >
typename std::enable_if<std::is_same<typename std::result_of<Fun()>::type, double>::value>::type f(Fun f) ...
等等......或者你可以使用标签调度:
template < typename Fun, typename Tag >
struct caller;
template < typename T > tag {};
template < typename Fun >
struct caller<Fun, tag<int>> { static void call(Fun f) { f(); } };
// etc...
template < typename Fun >
void f(Fun fun) { caller<Fun, typename std::result_of<Fun()>>::call(fun); }
这是标准中的缺陷。 见DR 2132 :
考虑以下:
#include <functional> void f(std::function<void()>) {} void f(std::function<void(int)>) {} int main() { f([]{}); f([](int){}); }
主要对f的调用是模棱两可的。 显然因为lambda中
std::function
的转换序列是相同的。 该标准规定赋予std::function
“的函数对象对于参数类型ArgTypes
应为Callable(20.8.11.2)并返回R
类型。” 它并没有说如果不是这种情况,构造函数不是重载集的一部分。
尝试使用函数指针作为参数:
A(int f()) { f_ = f; }
A(float g()) { g_ = g; }
template<class F,
class R=std::result_of_t<F&()>,
std::enable_if_t<std::is_convertible<R,int>{}&&(!std::is_convertible<R,float>{}||std::is_integral<R>{}),int> =0
>
A(F&&f):A(std::function<int()>(std::forward<F>(f))){}
template<class F,
class R=std::result_of_t<F&()>,
std::enable_if_t<std::is_convertible<R,float>{}&&(!std::is_convertible<R,int>{}||std::is_floating_point<R>{}, int> =0
>
A(F&&f):A(std::function<float()>(std::forward<F>(f))){}
A(std::function<int()> f) { f_ = f; }
A(std::function<float()> g) { g_ = g; }
这里我们采用不明确的情况,并将整数调度到int重载,并且非浮动到浮点数。
它可以转换为两者的情况,但既不是浮点也不是积分,仍然是模棱两可的。 他们应该这样做。
sfina条款可能很棘手。 如果它不起作用,请替换:
std::enable_if_t<std::is_convertible<R,float>{}&&(!std::is_convertible<R,int>{}||std::is_floating_point<R>{}, int> =0
同
class=std::enable_if_t<std::is_convertible<R,float>{}&&(!std::is_convertible<R,int>{}||std::is_floating_point<R>{}>
和其他类似的ctor。 例如,这可能在MSVC中有效。
由于2015年缺乏表达能力,msvc可能需要完整的标签调度。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.