C ++ 11 Lambda函数隐式转换为bool vs.std :: function [英] C++11 Lambda functions implicit conversion to bool vs. std::function

查看:162
本文介绍了C ++ 11 Lambda函数隐式转换为bool vs.std :: function的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下简单示例代码:

Consider this simple example code:

#include <functional>
#include <iostream>

void f(bool _switch) {
    std::cout << "Nothing really" << std::endl;
}

void f(std::function<double (int)> _f) {
    std::cout << "Nothing really, too" << std::endl;
}

int main ( int argc, char* argv[] ) {
    f([](int _idx){ return 7.9;});
    return 0;
}

无法编译:

$ g++ --std=c++11 main.cpp
main.cpp: In function ‘int main(int, char**)’:
main.cpp:15:33: error: call of overloaded ‘f(main(int, char**)::<lambda(int)>)’ is ambiguous
main.cpp:15:33: note: candidates are:
main.cpp:6:6: note: void f(bool)
main.cpp:10:6: note: void f(std::function<double(int)>)

但是,如果我将第二个函数替​​换为引用参数,则可以正常编译.再一次,如果将其替换为const引用,它将失败.

However if I replace the second function with a reference argument it compiles fine. And again if it is replaced by a const reference it fails.

所以我对这个例子有一些疑问:

So I have some questions concerning this example:

  • 为什么首先将lambda函数隐式转换为bool?
  • 为什么要使用std :: function引用来解决歧义?
  • 对我来说最重要的是,如何避免这个问题?我需要第二个函数采用std :: function(的a副本)或对其的const引用.

推荐答案

namespace details{
  template<class Sig,class=void>
  struct invoke {};
  template<class F, class...Args>
  struct invoke<F(Args...),decltype(void(
    std::declval<F>()(std::declval<Args>()...)
  ))>{
    using type=decltype(std::declval<F>()(std::declval<Args>()...));
  };
}
template<class Sig>struct invoke:details::invoke<Sig>{};

template<typename Sig, typename T, typename=void>
struct invoke_test:std::false_type {};
template<typename R, typename...Args, typename T>
struct invoke_test<R(Args...), T,
  typename std::enable_if<
    std::is_convertible<
      typename invoke<T(Args...)>::type,
      R
    >::value
  >::type
>:std::true_type {};
template<typename...Args,typename T>
struct invoke_test<void(Args...),T,
  decltype( void( typename invoke<T(Args...)>::type ) )
>:std::true_type{};
template<typename Sig, typename T>
constexpr bool invokable() {
  return invoke_test<Sig,T>::value;
}

这为我们提供了一个伪概念invokable.

this gives us a pseudo-concept invokable.

然后我们可以像这样使用它:

We can then use it like:

template<typename F>
typename std::enable_if<invokable<double(int),F>()>::type
f(F&&){
  std::cout << "can be invoked\n";
}
void f(bool) {
  std::cout << "is bool\n";
}

鲍勃是你的叔叔.

真正的问题是std::function<double(int)>的构造函数没有进行类似的测试,而是(错误地)声称可以从任何东西构造它.这是标准中的一个缺陷,我怀疑一旦概念标准化就可以解决.

The real problem is that std::function<double(int)> 's constructor does not do a similar test, and instead claims (falsely) that it can be constructed from anything at all. This is a flaw in the standard, one I suspect will be fixed once concepts are standardized.

这篇关于C ++ 11 Lambda函数隐式转换为bool vs.std :: function的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆