0

我在 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);
}

是否禁止使用带有转换的模板?

4

3 回答 3

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值。

于 2013-07-18T16:09:09.093 回答
1

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

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

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

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

或者可以禁止使用带有转换的模板?

这本身就是一个有趣的观点,因为它显示了一些常见的误解。Atemplate是创建其他元素的蓝图。在这种情况下,您有一个函数模板,它只是一个蓝图,编译器将通过替换模板参数从中生成不同的函数。在需要函数的任何上下文中,都不能使用函数模板,尽管可以使用专门化(即从该函数模板生成的函数)。

在某些情况下,您可以使用模板的名称来引用具体的特化,这会变得有些混乱。也就是说,在类模板定义(或它的成员的定义)中,模板的名称可以用来指代特。在函数模板的情况下,模板的名称可用于在编译器能够丢弃除其中一种特化之外的所有特化的上下文中引用函数模板的所有可能特化,例如:

int call(int (*ptr)(int)) { return ptr(5); }
call(reciprocal);       // [1]

在 [1] 中,reciprocal指的是函数模板的所有可能的特化,但这种特殊用途是允许的,因为这些特化中只有一个(即)可以用作 的参数。reciprocal<int>call

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

于 2013-07-18T16:09:48.073 回答
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)。

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

std::vector<double> vec(5, 2);
std::transform(vec.begin(), vec.end(), vec.begin(), reciprocal());
于 2013-07-18T16:28:20.870 回答