0

不完全是一个问题,虽然只是我一直在思考如何通过风格更优雅地编写这样的代码,同时充分利用新的 c++ 标准等。这是示例

将斐波那契序列返回到一个容器中最多 N 个值(对于那些不倾向于数学的人,这只是将前两个值相加,前两个值等于 1。即 1,1,2,3,5,8,13,.. .)

示例从 main 运行:

std::vector<double> vec;
running_fibonacci_seq(vec,30000000);

1)

template <typename T, typename INT_TYPE>
    void running_fibonacci_seq(T& coll, const INT_TYPE& N)
    {
        coll.resize(N);
        coll[0] = 1;
        if (N>1) {
        coll[1] = 1;
        for (auto pos = coll.begin()+2;
            pos != coll.end();
            ++pos)
        {
            *pos = *(pos-1) + *(pos-2);
        }
        }
    }

2) 相同,但使用右值&& 而不是 & 1.e。

void running_fibonacci_seq(T&& coll, const INT_TYPE& N)

编辑:正如下面评论的用户所注意到的,右值和左值在时间上没有任何作用——由于评论中讨论的原因,速度实际上是相同的

N = 30,000,000 的结果

Time taken for &:919.053ms

Time taken for &&: 800.046ms

首先,我知道这确实不是一个问题,但是其中哪个或哪个是最好的现代 C++ 代码?使用右值引用 (&&) 似乎移动语义已经到位,并且没有制作不必要的副本,这在时间上做了一个小的改进(对我来说很重要,因为未来的实时应用程序开发)。一些具体的“问题”是

a) 将容器(在我的示例中是向量)作为参数传递给函数并不是真正应该如何使用右值的优雅解决方案。这是真的吗?如果是这样,在上面的示例中,右值如何真正显示它的轻量级?

b) coll.resize(N); 调用和N=1的情况,有没有办法避免这些调用,所以给用户一个简单的界面,只使用函数而不动态创建向量的大小。可以在这里使用模板元编程,以便在编译时为向量分配特定大小吗?(即running_fibonacci_seq<30000000>)因为数字可能很大,是否需要使用模板元编程,如果可以的话,我们也可以使用这个(链接)

c) 有没有更优雅的方法?我有一种感觉 std::transform 函数可以通过使用lambdas来使用,例如

    void running_fibonacci_seq(T&& coll, const INT_TYPE& N)
    {
        coll.resize(N);
        coll[0] = 1;
        coll[1] = 1;
        std::transform (coll.begin()+2,
                coll.end(),         // source
                coll.begin(),       // destination
                [????](????) {      // lambda as function object
                    return ????????;
                });
    }

[1] http://cpptruths.blogspot.co.uk/2011/07/want-speed-use-constexpr-meta.html

4

3 回答 3

2

显而易见的答案:

std::vector<double> running_fibonacci_seq(uint32_t N);

为什么 ?

由于 const-ness:

std::vector<double> const result = running_fibonacci_seq(....);

因为更简单的不变量:

void running_fibonacci_seq(std::vector<double>& t, uint32_t N) {
    // Oh, forgot to clear "t"!
    t.push_back(1);
    ...
}

但是速度呢?

有一种称为返回值优化的优化允许编译器在许多情况下省略副本(并直接在调用者的变量中构建结果)。即使复制/移动构造函数有副作用,C++ 标准也明确允许这样做。

那么,为什么要传递“out”参数呢?

  • 你只能有一个返回值(叹气
  • 您可能希望重用分配的资源(这里是内存缓冲区t
于 2013-01-04T19:07:53.767 回答
2

由于“引用折叠”,此代码不使用右值引用,也不移动任何东西:

template <typename T, typename INT_TYPE>
void running_fibonacci_seq(T&& coll, const INT_TYPE& N);

running_fibonacci_seq(vec,30000000);

All of your questions (and the existing comments) become quite meaningless when you recognize this.

于 2013-01-04T19:24:00.217 回答
1

简介:

#include <vector>
#include <cstddef>
#include <type_traits>

template <typename Container>
Container generate_fibbonacci_sequence(std::size_t N)
{
    Container coll;
    coll.resize(N);
    coll[0] = 1;
    if (N>1) {
      coll[1] = 1;
      for (auto pos = coll.begin()+2;
        pos != coll.end();
        ++pos)
      {
        *pos = *(pos-1) + *(pos-2);
      }
    }
    return coll;
}

struct fibbo_maker {
  std::size_t N;
  fibbo_maker(std::size_t n):N(n) {}
  template<typename Container>
  operator Container() const {
    typedef typename std::remove_reference<Container>::type NRContainer;
    typedef typename std::decay<NRContainer>::type VContainer;
    return generate_fibbonacci_sequence<VContainer>(N);
  }
};

fibbo_maker make_fibbonacci_sequence( std::size_t N ) {
  return fibbo_maker(N);
}

int main() {
  std::vector<double> tmp = make_fibbonacci_sequence(30000000);
}

这些fibbo_maker东西只是我很聪明。但它可以让我推断出你想要的 fibbo 序列的类型,而不必重复它。

于 2013-01-04T19:17:40.453 回答