使用带变换的模板

时间:2013-07-18 16:06:08

标签: c++ templates stl transform

我在c ++中使用算法库的转换函数时遇到问题。我想使用一元模板函数,这意味着我的转换函数需要3个迭代器和函数作为参数。但是,我的程序崩溃了,编译器告诉我,我错过了一个没有意义的参数,因为我的函数是一元的而不是二进制操作。

我的代码如下:

template <typename T>
T reciprocal ( T value )
{ return (T)1/value ; }

int main()
{
    vector<int> vec(5, 2);
    transform(vec.begin(), vec.end(), vec.begin(), reciprocal);
}

是否禁止使用变换模板?

3 个答案:

答案 0 :(得分:2)

reciprocal是一个函数模板,std::transform无法确定要使用的特定专业化。您需要明确并为其提供模板参数:

transform(vec.begin(), vec.end(), vec.begin(), reciprocal<int>);

请注意,在您的情况下,您将执行整数除法1/2,这将为您提供一堆零。为了说明浮点倒数计算,以及reciprocal的模板参数不必与vec使用的模板参数相同,您可以尝试这样做:

std::vector<double> vec2;
std::transform(vec.begin(), 
               vec.end(), 
               std::back_inserter(vec2), 
               reciprocal<double>);

这将导致vec2包含五个0.5值。

答案 1 :(得分:1)

  

但我的程序崩溃了,编译器告诉我我错过了一个没有意义的参数,因为我的函数是一元的而不是二元运算

你应该清楚地说明你的程序是否编译然后崩溃,而不是编译,编译器崩溃以及缺少什么类型的参数。

现在猜测你的意思,问题是transform模板没有对最后一个参数施加任何限制,因此编译器无法确定{{1}的哪些重载(特化)应该传递给转换模板。您可以手动指定您想要的那个:

reciprocal

  

或者禁止使用带变换的模板?

这是一个有趣的观点,因为它显示了一些常见的误解。 transform(vec.begin(), vec.end(), vec.begin(), &reciprocal<int>); 是创建其他元素的蓝图。在这种情况下,您有一个函数模板,它只是一个蓝图,编译器将通过替换模板参数生成不同的函数。在需要功能的任何环境中,不能使用功能模板,尽管专门化(即功能 >可以使用>从功能模板生成)。

在某些情况下,您可以使用模板的名称来引用具体的专业化,这会让您感到有些困惑。即,在类模板定义(或其成员的定义)内,模板的名称可用于引用专门化。对于功能模板,模板的名称可用于在那些上下文中引用功能模板所有可能的特化编译器将能够丢弃除这些特化之外的所有特殊化,例如:

template

在[1]中,int call(int (*ptr)(int)) { return ptr(5); } call(reciprocal); // [1] 指的是 功能模板的所有可能的特殊化,但这种特殊用途仅允许作为其中一个特征(即reciprocal)可以用作reciprocal<int>的参数。

但这些是例外,主要的一点是类模板函数模板不是函数但是编译器可以从中创建类和函数的生成器。

答案 2 :(得分:0)

现在,您依赖于编译器来推断实例化reciprocal的正确类型,但由于您未指定参数类型,因此无法执行此操作。

你可以通过指定正确的类型来解决这个问题,正如@jaunchopanza已经指出的那样。通过稍微不同地构造代码:

struct reciprocal {
    template <typename T>
    T operator()(T value)
    { 
        return (T) 1 / value; 
    }
};

...你可以让编译器推断出类型,所以代码如下:

std::transform(vec.begin(), vec.end(), vec.begin(), reciprocal());

...正常工作(虽然请注意用于创建reciprocal的实例的parens。)

当然,int上的倒数通常没有多大意义 - 它可以产生的全部是0或1(或输入0的未定义行为)。您可能希望使用浮点类型来获得有意义的结果:

std::vector<double> vec(5, 2);
std::transform(vec.begin(), vec.end(), vec.begin(), reciprocal());