将 lambda(int)->int 转换为 std::function<int(float)>

Converting lambda(int)->int to std::function<int(float)>

为什么 C++ 编译器不针对此代码给出警告或错误?

    std::function<int(float)> f = [](int x) -> int {
        return x*x;
    };

    std::cout << f(4.2) << '\n';

有没有办法防止这种含蓄的对话? (例如编写包装器或辅助方法以生成错误)

Why C++ compiler doesn't give warning or error for this code?

针对此类情况的 gcc 编译器选项通常是 -Wconversion,但它似乎不适用于您的特定情况。我尝试了很多其他标志但没有成功。但是,您可以使用 MSVC 获得警告级别 4 的综合警告。

为什么会报错?这将与 std::function 的一个主要目的相矛盾,即从允许的隐式转换中获益,以保持作为一般函子持有者的灵活性,并且有疑问,您可以通过签名自行使事情变得更加明确检查器特征。对于 std::function,它可能看起来像这样(“旧的”C++17 之前的方法,通用 Lambda 和重载的一些缺点,请参阅评论):

template <typename ProvidedSignature, typename RequiredSignature>
struct SignatureMatches :  std::false_type
{};

template <typename R1, typename R2>
struct SignatureMatches<R1(), R2()> : std::is_convertible<R2, R1>
{};

template <typename R1, typename R2, typename Arg1, typename Arg2, typename... Args1, typename... Args2>
struct SignatureMatches<R1(Arg1, Args1...), R2(Arg2, Args2...)>
  : std::conditional_t<
      std::is_convertible_v<std::remove_cv_t<std::remove_reference_t<Arg1>>, std::remove_cv_t<std::remove_reference_t<Arg2>>>,
      SignatureMatches<R1(Args1...), R2(Args2...)>,
      std::false_type>
{};

template <typename R1, typename R2, typename... Args1, typename... Args2>
struct SignatureMatches<R1(Args1...) noexcept, R2(Args2...) noexcept>
  : SignatureMatches<R1(Args1...), R2(Args2...)>
{};

为了您自己的目的,您只需更改

std::is_convertible_v<std::remove_cv_t<std::remove_reference_t<Arg1>>, std::remove_cv_t<std::remove_reference_t<Arg2>>>

更严格的方案,可能通过 std::is_same

另请参阅标准对可调用对象的定义和要求:Callable