标签: std-function

Clang 实现 std::function 移动语义背后的推理

libc++的实现中std::function,如果要擦除其类型的函数对象足够小以适合 SBO,则移动操作将复制它,而不是移动它。然而,并不是每个堆栈内存占用较小的对象都适合复制。为什么要复制而不是移动?

使用 Clang 考虑这个示例(使用shared_ptr它是因为它具有引用计数):

https://wandbox.org/permlink/9oOhjigTtOt9A8Nt

中的语义与使用显式副本test1()的语义相同。帮助我们看到这一点。test3()shared_ptr

另一方面,GCC 的行为是合理且可预测的:

https://wandbox.org/permlink/bYUDDr0JFMi8Ord6

两者都是标准允许的。std::function要求函数可复制,移出的对象处于未指定状态,等等。为什么要这么做?同样的推理也适用于std::map:如果键和值都是可复制的,那么为什么不每当有人std::movesa时就制作一个新副本std::map?这也符合标准的要求。

根据cppreference.com 的说法,应该有一个举动,并且应该是目标。

这个例子:

#include <iostream>
#include <memory>
#include <functional>
#include <array>
#include <type_traits>

void test1()
{
    /// Some small tiny type of resource. Also, `shared_ptr` is used because it has a neat
    /// `use_count()` feature that will allow us to see what's going on behind the 'curtains'.
    auto foo …
Run Code Online (Sandbox Code Playgroud)

c++ clang std-function libc++ c++20

31
推荐指数
1
解决办法
1932
查看次数

如何表示和传递C++ 11 lambdas?

在c ++ 11中传递lambda非常简单:

func( []( int arg ) {
  // code
} ) ;
Run Code Online (Sandbox Code Playgroud)

但我想知道,将lambda传递给像这样的函数的成本是多少?如果func将lambda传递给其他函数怎么办?

void func( function< void (int arg) > f ) {
  doSomethingElse( f ) ;
}
Run Code Online (Sandbox Code Playgroud)

lambda的传递是否昂贵?由于可以function对象分配0,

function< void (int arg) > f = 0 ; // 0 means "not init" 
Run Code Online (Sandbox Code Playgroud)

它让我认为函数对象就像指针一样.但是,如果不使用new,则意味着它们可能类似于值类型struct或类,它们默认为堆栈分配和成员方式副本.

当你按"值"传递一个函数对象时,C++ 11"代码体"和捕获的变量组是如何传递的?是否有很多代码体的多余副本?我是否必须标记function传递的每个对象,const&以便不进行复制:

void func( const function< void (int arg) >& f ) {
}
Run Code Online (Sandbox Code Playgroud)

或者以某种方式使函数对象以不同于常规C++结构的方式传递?

c++ lambda parameter-passing c++11 std-function

30
推荐指数
1
解决办法
2830
查看次数

lambda的Lambda:未捕获该函数

以下程序不编译:

#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>
#include <cstdlib>
#include <cmath>

void asort(std::vector<double>& v, std::function<bool(double, double)> f)
{
    std::sort(v.begin(), v.end(), [](double a, double b){return f(std::abs(a), std::abs(b));});
}

int main()
{
    std::vector<double> v({1.2, -1.3, 4.5, 2.3, -10.2, -3.4});
    for (unsigned int i = 0; i < v.size(); ++i) {
        std::cout<<v[i]<<" ";
    }
    std::cout<<std::endl;
    asort(v, [](double a, double b){return a < b;});
    for (unsigned int i = 0; i < v.size(); ++i) {
        std::cout<<v[i]<<" ";
    }
    std::cout<<std::endl;
    return 0;
} …
Run Code Online (Sandbox Code Playgroud)

c++ lambda c++11 std-function

29
推荐指数
2
解决办法
3万
查看次数

在标准下调用std :: function <void(Args ...)>是违法的吗?

所有报价均来自N3797.

4/3 [转]

当且仅当声明T t = e时,表达式e可以隐式转换为类型T. 对于一些发明的临时变量t而言,其形式良好

这意味着没有表达式可以隐式转换为void,这void t=e对所有表达式都是非法的e.如果e是类型的表达式void,例如,这甚至是真的void(3).

所以类型的表达式void不能隐式转换为void.

这导致我们:

20.9.2/2要求[func.require]

将INVOKE(f,t1,t2,...,tN,R)定义为隐式转换为R的INVOKE(f,t1,t2,...,tN).

总之,INVOKE(f, t1, t2, ..., tN, R)当是永远有效Rvoid,如无(含void)可以隐式转换为void.

因此,所有都std::function<void(Args...)>具有属性!*this,因此不能被调用,因为唯一没有!*this后置条件的构造函数(或者不从function相同类型的另一个复制此类状态)需要Callable其中一个参数.

20.9.11.2/7类模板函数[func.wrap.func]

要求:F应为CopyConstructible.对于参数类型ArgTypes,f应为Callable(20.9.11.2)并返回R类型.A的拷贝构造函数和析构函数不应抛出异常.

20.9.11.2/2类模板函数[func.wrap.func]

类型F的可调用对象f对于参数类型ArgTypes是Callable,如果表达式INVOKE(f,declval()...,R)被认为是未评估的操作数(第5条),则返回类型R( 20.9.2).

如上所述,没有Callable表达std::function<void(Args...)>.

如果以某种方式std::function<void(Args...)>找到这样的地方,调用operator()将会形成错误:

调用[func.wrap.func.inv]

效果:INVOKE(f,std :: forward(args)...,R)(20.9.2),其中f是*this的目标对象(20.9.1).

因为INVOKE(f, …

c++ language-lawyer c++11 std-function c++14

27
推荐指数
1
解决办法
863
查看次数

如果返回一个向量项,那么lambda表达式的返回类型是什么?

请考虑以下代码段:

#include <iostream>
#include <vector>
#include <functional>

int main() 
{
    std::vector<int>v = {0,1,2,3,4,5,6};
    std::function<const int&(int)> f = [&v](int i) { return v[i];}; 
    std::function<const int&(int)> g = [&v](int i) -> const int& { return v[i];};

    std::cout << f(3) << ' ' << g(3) << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我期待相同的结果:in f,v由const引用传递,所以v[i]应该有const int&类型.

但是,我得到了结果

 0 3
Run Code Online (Sandbox Code Playgroud)

如果我不使用std :: function,一切都很好:

#include <iostream>
#include <vector>
#include <functional>

int main() 
{
    std::vector<int>v = {0,1,2,3,4,5,6};
    auto f = [&v](int i) …
Run Code Online (Sandbox Code Playgroud)

c++ lambda c++11 std-function return-type-deduction

27
推荐指数
3
解决办法
3320
查看次数

Fast Delegate(等)背后的想法是否用于优化std :: function?

已经提出了C++"委托"的建议,其开销低于boost::function:

是否已将这些想法用于实施std::function,从而产生更好的性能boost::function?有谁比较过std::functionvs 的表现boost::function

我想知道这个特别适用于英特尔64位架构上的GCC编译器和libstdc ++,但欢迎其他编译器的信息(例如Clang).

c++ performance boost c++11 std-function

22
推荐指数
1
解决办法
2788
查看次数

获取std :: function的名称

在下面的玩具示例中,我想获得一个函数的名称.函数本身作为std::function参数给出.在C++中是否可以获取std::function对象的名称?

void printName(std::function<void()> func){
    //Need a function name()
    std::cout << func.name();
}

void magic(){};

//somewhere in the code
printName(magic());

output: magic
Run Code Online (Sandbox Code Playgroud)

否则我必须将函数的名称作为第二个参数.

c++ c++11 std-function

21
推荐指数
3
解决办法
5902
查看次数

在C++中使用'void'模板参数

采取以下最小例子:

using Type1 = std::function<void(void)>;

template <typename T>
using Type2 = std::function<void(T)>;

Type1 whyDoesThisWork;
Type2<void> andYetThisDoesNot;
Run Code Online (Sandbox Code Playgroud)

如果第二个类型别名,我得到错误"参数可能没有'void'类型".(我使用Xcode 4.5,Clang/c ++ 11/libc ++,OS X 10.7进行了测试.)

我发现这很奇怪:我本来期望Type1并且Type2<void>行为相同.这里发生了什么?有没有办法重写第二类型别名,所以我可以编写Type2<void>并获取std::function<void(void)>而不是错误?

编辑我应该补充一点,我想要的原因是允许以下内容:

template <typename ... T>
using Continuation = std::function<void(T...)>;

auto someFunc = []() -> void {
  printf("I'm returning void!\n");
};

Continuation<decltype(someFunc())> c;
Run Code Online (Sandbox Code Playgroud)

Continuation<decltype(someFunc())>成为Continuation<void>,我得到了错误.

c++ templates c++11 std-function

20
推荐指数
3
解决办法
3万
查看次数

通过std :: function引用的Functor

基本上,我想有以下语义:

#include <functional>
#include <iostream>

class test
{
  public:
    void add(std::function<void()> f)
    {
      f();
    }

    void operator()()
    {
      ++x;
    }

    int x = 33;
};

int main()
{
  test t;
  t.add(t);
  // wanted: x == 34 instead: x == 33 since add(t) copies it
}
Run Code Online (Sandbox Code Playgroud)

我理解std :: function包装了一个可调用对象的副本,但有没有办法使用std :: function获取对可调用对象的引用?

c++ c++11 std-function

20
推荐指数
1
解决办法
4494
查看次数

使用`std :: function <void(...)>`来调用非void函数

前一段时间我用std::function的很像:

std::function<void(int)> func = [](int i) -> int { return i; };
Run Code Online (Sandbox Code Playgroud)

基本上,我这样做是因为我想在a中存储不同的函数对象std::function,但我不想限制这些函数的返回类型.由于这似乎有效,我接受了它.但我不相信它是安全的,我也无法找到任何文件.有谁知道这种用法是否合法?或者更一般地说,对象的规则是什么,可以安全地分配给std::function

编辑

为了澄清,我关心的问题是lambda函数返回一个int,而func声明返回类型void.我不确定这是否正常,特别是一旦打电话func().

c++ return-type c++11 std-function

19
推荐指数
1
解决办法
6574
查看次数