模板函数中引用类型的推导

时间:2009-02-05 12:57:09

标签: c++ templates

在引用类型推导时,是否必须显式实例化函数模板的类型。如果是这样的话,歧义在哪里?让我们比较以下2个代码片段:

第一名:link for the code

template <typename T> 
void foo(T& var, void(*func)(T&)) // T must be instantiated with int and it does .
{
 ++var;
} 
void ret(int & var){}
int main()
{int k =7; 
foo(k, &ret);
cout<<k;//prints 8
}

现在让我们在foo()中删除&amp;'s,我们有一个错误。

第二名:link for the code

template <typename T> 
void foo(T var, void(*func)(T)) // T must be instantiated with int& but it doesn't.
{
 ++var;
} 

void ret(int & var){}

int main()
{int k =7; 

foo(k, &ret); //error: no matching function for call to 'foo(int&, void (*)(int&))'
cout<<k;
}

但是,如果我通过使用<int&>foo<int&>(k,&ret);”显式实例化来调用foo,则代码将提供与前者相同的输出。这个错误的原因是什么?歧义在哪里?

感谢。

2 个答案:

答案 0 :(得分:3)

正如Fionn的answer所强调的那样,问题是编译器为 T int int&amp; 。 18.8.2.4/2具有以下内容:

  

在某些情况下,扣除是使用一组P和A类型完成的,在其他情况下,会有一组   相应的类型P和A.类型推导是针对每个P / A对独立完成的,并推导出   然后组合模板参数值。如果不能对任何P / A对进行类型扣除,或者如果为   任何一对推导导致一组以上可能的推导值,或者如果不同的对产生不同   推导出的值,或者如果任何模板参数既未推断也未明确指定,则为模板   论证推论失败。

我认为突出显示的文字涵盖了您的示例。您没有问,但您可能有一个选项是在示例中使用两个模板参数。这两种情况都可以推断出来,因此您可以使用其他一些模板技巧,可以通过启用if if创建一个代表您想要的版本的新类型,即。参考或不参考。

答案 1 :(得分:1)

答案的第二个版本,只是误解了这个问题:

第二个版本的问题是编译器无法知道您是想通过引用传递还是传递值。

两者的调用语法完全相同,但你显然希望通过引用传递 - 否则增量没有任何意义。

这里有一个例子来说明如何通过引用传递函数和使用pass by value参数调用函数没有区别:

void Incr1(int &value) { value++; }
void Incr2(int value) { value++ } //Completely useless but for demonstration

//Now the calling of both functions
int x = 1;
Incr1(x);
Incr2(x);

如果您使用指针而不是引用,编译器会知道该怎么做,因为您明确告诉它您将指针传递给int。

#include <iostream>

template <typename T> 
void foo(T var, void(*func)(T))
{
    ++(*var);
} 

void ret(int *var){}

int main()
{
    int k =7; 

    foo(&k, &ret); 
    std::cout<<k;
}

这将使它编译,但它没有多大意义:

错误是您的功能仍然需要T&amp;而不是T。

所以你只需要这个小修改:

template <typename T> 
void foo(T var, void(*func)(T&))
{
 ++var;
} 

void ret(int & var){}

int main()
{
    int k =7; 

    foo(k, &ret);
    std::cout<<k;
}