【问题标题】:Template deduction: porting to C++11模板推演:移植到C++11
【发布时间】:2017-03-29 06:29:38
【问题描述】:

以下代码对于 C++14 编译器是合法的

// g++ -std=c++14 -pedantic -pthread main.cpp
// output: 1 2 3 4 5 1 1 1 
#include <algorithm>
#include <vector>
#include <functional>
#include <iterator>
#include <iostream>

int main()
{
  std::vector<int> a = { 1, 2, 3, 2, 4, 5, 1, 1, 3, 5, 1, 5 }, b = { 2, 5, 5, 3 }, c;

  std::copy_if(a.begin(), a.end(), std::back_inserter(c), 
    std::bind(std::less<>(),   // this won't work in pre-C++14
      std::bind(
        std::count<std::vector<int>::iterator, int>, 
          std::bind(static_cast<std::vector<int>::iterator (std::vector<int>::*)()>(&std::vector<int>::begin), &c), 
          std::bind(static_cast<std::vector<int>::iterator (std::vector<int>::*)()>(&std::vector<int>::end), &c), 
          std::placeholders::_1
      ),
      std::bind(
        std::minus<>(), // this won't work in pre-C++14
          std::bind(
            std::count<std::vector<int>::iterator, int>, 
              a.begin(), 
              a.end(), 
              std::placeholders::_1
          ),
          std::bind(
            std::count<std::vector<int>::iterator, int>, 
              b.begin(), 
              b.end(), 
              std::placeholders::_1
          )
      )
    )
  );

  std::copy(c.begin(), c.end(), std::ostream_iterator<int>(std::cout, " "));
  std::cout << std::endl;
}

这意味着从向量 a 的元素创建向量 c,不包括那些匹配向量 b 中元素的计数和值的元素。例如。如果 a 包含三个 2 和 b - 其中两个,则 c 中只会出现一个 2。

a) 如何将这段代码改编为 C++11? less 和 minus 参数将是 ...::difference_type 的直观飞跃不起作用,编译器消息也没有帮助

b) 当前版本按顺序删除最后一个匹配项。什么代码会删除 first 个匹配项?

【问题讨论】:

  • 哇哦,std::bind。请不要使用它(在 c++11 和 c++14 中)
  • 改为使用 lambda,但我想说你也需要重新考虑你的算法
  • 现在对于真正的题外话,here 是我将如何实现它。当然,如果你不需要保留顺序,那么也许还有更好的方法
  • @Ap31: std::set_difference 如果不需要原始订单,可以使用。
  • 很明显,这一点在你脑海中浮现,所以我会再试一次:在 C++11 中编写一个与 C++14 minus&lt;&gt; 具有相同功能的类型是微不足道的大约五行代码。如果你有这么多问题,那就自己去实现吧。

标签: c++ c++11 c++14 stdbind


【解决方案1】:

真正的答案是不要使用bind()。使用 lambda:

std::copy_if(a.begin(), a.end(), std::back_inserter(c), [&](int elem){
    return std::count(c.begin(), c.end(), elem) <
        std::count(a.begin(), a.end(), elem) - std::count(b.begin(), b.end(), elem);
});

std::bind()的解决方案短,在C++11中工作,并且更容易理解。而且我们也不必手动推模。

我们也可以这样写:

std::copy_if(a.begin(), a.end(), std::back_inserter(c), [&](int& elem){
    return std::count(&elem + 1, &a[a.size()], elem) >=
        std::count(b.begin(), b.end(), elem);
});

请注意,我现在将elem 作为参考。这也使您更容易了解如何实施您建议的扩展来删除第一个匹配项。这只是改变了我们比较aelem 的哪一边:

std::copy_if(a.begin(), a.end(), std::back_inserter(c), [&](int& elem) {
    return std::count(&a[0], &elem, elem) >=
        std::count(b.begin(), b.end(), elem);
});

【讨论】:

  • 为什么是&amp;a[0]?有data 问题吗?
  • @Yakk 比其他版本更短更对称。
  • 但我的问题是我不能放弃至少一个最高绑定和 lcc(分布式 sparc 编译器)并与之兼容 vc 2010 编译器不接受 less<:difference_type>(),它有效使用完全 c++11 编译器,替代 less 的简单实现都不起作用
  • @Swift 嗯?我不知道那是什么意思。
  • 投票支持我没想到的替代 lambda 版本。我想,解决第二部分最简单的部分是获取支持前推的容器......例如标准::列表。问题的表述是这样的,它代表了完全不能通过使用闭包来解决的现实问题,因为如果某些代码不可用,则某些代码不可移植,并且目标平台包括 spark 系统、x64 linux(所有东西都可以使用 atm)和 win7 嵌入式用vc2010
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-25
  • 1970-01-01
  • 1970-01-01
  • 2021-03-01
  • 1970-01-01
相关资源
最近更新 更多