为什么这个重载函数调用模糊不清?

时间:2016-02-08 22:19:03

标签: c++ c++11 lambda stl

为什么这个构造函数调用不明确?

#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;
}

请注意类型转换。

有没有办法告诉编译器使用哪个构造函数重载?

3 个答案:

答案 0 :(得分:3)

因为您传递的内容与类型不匹配所以我们进入转换序列以找到要使用的重载。可以从返回int的lambda对象隐式创建两个版本的函数。因此,编译器无法决定选择创建哪个;虽然看起来很直观,但C ++中的规则并不允许这样做。

编辑:

写下袖口,但我认为这可以解决问题:

public void readJSON(String jsonString){
    try {
        JSONObject object = new JSONObject(jsonString);
        String name = object.getString("name");
        String surname = object.getString("surname");
    } catch (JSONException e){
        e.printStackTrace();
    }
}

等......或者你可以使用标签调度:

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) ...

答案 1 :(得分:3)

这是标准中的缺陷。见DR 2132

  

请考虑以下事项:

#include <functional>

void f(std::function<void()>) {}
void f(std::function<void(int)>) {}

int main() {
  f([]{});
  f([](int){});
}
     

主要对f的调用含糊不清。显然是因为   从lambdas到std::function的转换序列是   相同。该标准指定给出的函数对象   对于参数类型,std::function“应为Callable(20.8.11.2)   ArgTypes并返回类型R。“如果不是这样,则不会说明   在这种情况下,构造函数不是重载集的一部分。

尝试使用函数指针作为参数:

A(int f()) { f_ = f; }
A(float g()) { g_ = g; }

答案 2 :(得分:0)

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可能需要完整的标签调度。