模板函数,用于向集合的每个元素添加值

时间:2012-12-30 21:19:10

标签: c++ templates

我正在阅读C++ Templates: The complete guide书,第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构建它 演员表是不正确的还是问题还有什么呢?

2 个答案:

答案 0 :(得分: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 - 向量将具有更好的性能,因为它将避免在添加项目时进行内部重新分配。另一种方法是调用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
);

答案 1 :(得分:2)

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

  1. 您可以在dest数据之前设置std::transform()的大小:dest.resize(source.size())
  2. 您可以使用deststd::back_insert_iterator<...>指示算法在std::transform(source.begin(), source.end(), std::back_inserter(dest), function)末尾插入对象(其中function是获取函数的合适方法对象)。
  3. 就个人而言,我不会使用指向函数的指针,因为很可能编译器不会通过指向函数的指针来内联函数调用。相反,我会使用合适的函数对象:

    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>());