C++ 如何使用标准库算法`std::bind()`?

C++ 如何使用标准库算法`std::bind()`?,c++,c++11,c++14,c++17,C++,C++11,C++14,C++17,我的问题的简短版本是:如何将类似std::bind()的东西与标准库算法结合使用 由于短版本有点缺乏细节,这里有一个解释:假设我有算法 STD::Trase:(/Cuffe),现在我想实现 STD::Copy[] /Cuth>(是的,我意识到在标准C++库中有 STD::Copy[O]:/Cuff>)。由于我非常懒惰,我显然希望使用现有的std::transform()实现。当然,我可以这样做: struct identity { template <typename T>

我的问题的简短版本是:如何将类似
std::bind()
的东西与标准库算法结合使用

由于短版本有点缺乏细节,这里有一个解释:假设我有算法<代码> STD::Trase:(/Cuffe),现在我想实现<代码> STD::Copy[] /Cuth>(是的,我意识到在标准C++库中有<代码> STD::Copy[O]:/Cuff>)。由于我非常懒惰,我显然希望使用现有的

std::transform()
实现。当然,我可以这样做:

struct identity {
    template <typename T>
    auto operator()(T&& value) const -> T&& { return std::forward<T>(value); }
};  
template <typename InIt, typename OutIt>
auto copy(InIt begin, InIt end, OutIt to) -> OutIt {
    return std::transform(begin, end, to, identity());
}
问题在于,编译器不能仅从算法中确定适当的模板参数,并且无论是否存在
&
。有什么东西可以让像使用
std::bind()
这样的方法起作用吗?由于这是前瞻性的,我很高兴能与任何已经提出的包含在C++标准中的任何解决方案一起工作。另外,为了摆脱我的懒惰,我很乐意提前做一些工作,以便以后更容易使用。可以这样想:在我作为库实现者的角色中,我将把东西放在一起一次,这样每个库用户都可以变得懒惰:我是一个忙碌的实现者,但却是一个懒惰的用户

如果你想有一个现成的试验台:这里有一个完整的程序

#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <utility>
#include <vector>

using namespace std::placeholders;

struct identity {
    template <typename T>
    T&& operator()(T&& value) const { return std::forward<T>(value); }
};


int main()
{
    std::vector<int> source{ 0, 1, 2, 3, 4, 5, 6 };
    std::vector<int> target;

#ifdef WORKS
    std::transform(source.begin(), source.end(), std::back_inserter(target),
                   identity());
#else
    // the next line doesn't work and needs to be replaced by some magic
    auto copy = std::bind(&std::transform, _1, _2, _3, identity());
    copy(source.begin(), source.end(), std::back_inserter(target));
#endif
    std::copy(target.begin(), target.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << "\n";
}
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std::占位符;
结构标识{
模板
T&&operator()(T&&value)const{return std::forward(value);}
};
int main()
{
向量源{0,1,2,3,4,5,6};
std::载体靶;
#ifdef有效
std::transform(source.begin()、source.end()、std::back_插入器(target),
身份();
#否则
//下一行行不通,需要用一些魔法来代替
自动复制=std::bind(&std::transform,_1,_2,_3,identity());
复制(source.begin()、source.end()、std::back_插入器(目标));
#恩迪夫
std::copy(target.begin()、target.end()、std::ostream_迭代器(std::cout“”);

STD::P> >尝试<代码> STD::bDUDE()/C++ >一个重载函数。编译器不能确定使用哪一个过载:在<>代码> bDUDE()/代码>表达式被评估时,函数参数是未知的,即,过载分辨率不能决定要选择哪个超负荷。C++中没有直接的方法[/o?]函数模板只为每个可能的实例化生成一个重载集,其中一个重载是不能满足<代码> STD::BDUE()/<代码>的任何标准C++库算法围绕着标准库算法是函数模板的事实。 一种与算法绑定具有相同效果的方法是使用C++14通用lambda进行绑定,例如:

auto copy = [](auto&&... args){
    return std::transform(std::forward<decltype(args)>(args)..., identity());
};
尽管外观和使用了通用lambda,但值得指出的是,仅使用C++11可用的功能创建相应的函数对象实际上需要大致相同的努力:

struct transform_t {
    template <typename... Args>
    auto operator()(Args&&... args) const
        -> decltype(std::transform(std::forward<decltype(args)>(args)...)) {
        return std::transform(std::forward<decltype(args)>(args)...);
    }
};
constexpr transform_t transform{};
现在,假设
curry\u last()
位于同一名称空间中,则
nstd::transform
identity()
的定义可能是:

auto const copy = curry_last(nstd::transform, identity());

好的,也许这个问题没有给我任何帮助,但也许我会得到一些支持,将我们的标准库算法转化为函数对象,并可能添加一些很酷的方法来创建所述算法的绑定版本。我认为这种方法更理智(尽管在上面描述的形式中可能没有那么完整)比这一区域的一些s要高。

@πάνταῥεῖ: 嘿-这是一个真正的问题…!(当然,双重目标确实起到了作用)标签组合是,什么让我怀疑;-)…(这当然是一个好问题)泛型lambda几乎是我能想到的唯一一件事,但我认为这还不够
bind
-比如…你一定听说过通过泛型lambda传递重载集的C++14技术。这种方法有什么错或不足之处?@dyp:你想使用宏吗?哎呀…!不过,是的,这更接近我的想法而且,我目前正在尝试获得类似的工作,而且我现在使用的实现似乎并不完全满足转发占位符的需要。非标准扩展(甚至是好的扩展)的存在并不意味着它是C++所需要的!(标准不要求在无状态lambda上创建/移动/复制构造函数。@Yakk:是的,我被一个扩展欺骗了(实际上只有在gcc中,而不是在clang中)。@Yakk lambda可能不会出现在常量表达式中,我想这排除了“它是允许的,但不可移植的”@dyp:是的,你是对的。我把它们改成了
const
。不过,我不太喜欢这样:在正常初始化之前不能构造,这意味着即使使用C++14,也需要使用使用正确的函数对象而不是泛型lambda的方法…@Yakk闭包类型根据[expr.prim.lambda]显式地不是文本类型/p3和
constexpr
对象声明需要文本类型([dcl.constexpr]/p9)。
auto copy = std::bind(nstd::transform, P::_1, P::_2, P::_3, identity());
struct transform_t {
    template <typename... Args>
    auto operator()(Args&&... args) const
        -> decltype(std::transform(std::forward<decltype(args)>(args)...)) {
        return std::transform(std::forward<decltype(args)>(args)...);
    }
};
constexpr transform_t transform{};
template <typename Fun, typename Bound>
auto curry_last(Fun&& fun, Bound&& bound) {
    return [fun = std::forward<Fun>(fun),
            bound = std::forward<Bound>(bound)](auto&&... args){
        return fun(std::forward<decltype(args)>(args)..., bound);
    };
}
auto const copy = curry_last(nstd::transform, identity());