2

我正在阅读C++ 模板:完整指南,在第 4 章(4.2 非类型函数模板参数)中是模板函数的示例,可与 STL 容器一起使用,为集合的每个元素添加值。这是完整的程序:

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


template<typename T, int VAL>
T addValue(T const& x)
{
    return x + VAL;
}

int main()
{
    std::vector<int> source;
    std::vector<int> dest;
    source.push_back(1);
    source.push_back(2);
    source.push_back(3);
    source.push_back(4);
    source.push_back(5);

    std::transform(source.begin(), source.end(), dest.begin(), (int(*)(int const&)) addValue<int, 5>);
    std::copy(dest.begin(), dest.end(), std::ostream_iterator<int>(std::cout, ", "));

    return 0;
}

我不得不做出那个丑陋的演员,因为这本书说:

Note that there is a problem with this example: addValue<int,5> is a function template, and function templates are considered to name a set of overloaded functions (even if the set has only one member). However, according to the current standard, sets of overloaded functions cannot be used for template parameter deduction. Thus, you have to cast to the exact type of the function template argument:

std::transform (source.begin(), source.end(),  // start and end of source 
                dest.begin(),                  // start of destination 
                (int(*)(int const&)) addValue<int,5>);  // operation 

我的问题是运行程序时出现分段错误。我在 Mac 上使用 Clang 构建它。
演员表不正确还是问题可能是什么?

4

2 回答 2

3

演员表不是你的问题,你正在将元素输出到一个空的vector. 相反,您可以resize使用所需的空间:

dest.resize(source.size());

或者更好的是让我们transform弄清楚:

std::transform(
    source.begin(), source.end()
  , std::back_inserter( dest ) // needs <iterator>
  , &addValue<int, 5> // cast should not be needed
);

尽管如果您确实知道它将占用多少空间,则resize-ing 向量将具有更好的性能,因为它将避免在添加项目时进行内部重新分配。另一种选择是调用reserve以避免内部重新分配:

dest.reserve(source.size());
// dest is still empty

std::transform(
    source.begin(), source.end()
  , std::back_inserter( dest ) // needs <iterator>
  , &addValue<int, 5> // cast should not be needed
);
于 2012-12-30T21:23:05.567 回答
2

分段错误的问题是它dest是空的,但您正在为它分配值!有两种方法可以确保您可以实际分配元素:

  1. 您可以设置数据dest之前的大小std::transform()dest.resize(source.size())
  2. dest您可以指示算法在使用std::back_insert_iterator<...>:的末尾插入对象std::transform(source.begin(), source.end(), std::back_inserter(dest), function)(这function是获取函数对象的合适方法)。

就个人而言,无论如何我都不会使用指向函数的指针,因为编译器很可能不会通过指向函数的指针来内联函数调用。相反,我会使用一个合适的函数对象:

template <int N>
struct addValue {
    template <typename T>
    T operator()(T value) const { return value + N; }
};

...然后就使用

std::transform(source.begin(), source.end(), std::back_inserter(dest), addValue<5>());
于 2012-12-30T21:28:04.257 回答