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

C++ 模板函数中引用类型的推导,c++,templates,C++,Templates,当涉及引用类型推断时,是否必须显式实例化函数模板的类型。如果是这样的话,歧义在哪里?让我们比较以下两个代码段: 第一: 模板 void foo(T&var,void(*func)(T&)//T必须用int实例化,它确实是。 { ++var; } void ret(int&var){} int main() {int k=7; 傅(k,ret),; cout答案的第二个版本,只是误解了这个问题: 第二个版本的问题是,编译器无法知道是要按引用传递还是按值传递 两者的调用语法完全相同,但您显然希望通

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

第一:

模板
void foo(T&var,void(*func)(T&)//T必须用int实例化,它确实是。
{
++var;
} 
void ret(int&var){}
int main()
{int k=7;
傅(k,ret),;

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

第二个版本的问题是,编译器无法知道是要按引用传递还是按值传递

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

下面是一个示例,说明如何调用具有“按引用传递”和“按值传递”参数的函数没有区别:

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;
}
#包括
模板
无效foo(T变量,无效(*func)(T))
{
++(*var);
} 
void ret(int*var){}
int main()
{
int k=7;
foo&k&ret;
std::cout正如Fionn中强调的那样,问题在于编译器推导出T的两种不同类型,int和int&.18.8.2.4/2具有以下特性:

在某些情况下,使用一组p和a类型进行扣减,在其他情况下,将有一组 对应的类型P和A。对每个P/A对分别进行类型推导,推导出 然后组合模板参数值。如果无法对任何P/A对进行类型推断,或如果 任何一对推导都会导致多个可能的推导值集,或者如果不同的对产生不同的值 推导出的值,或者如果任何模板参数既未推导也未显式指定,则使用模板 论证推理失败


我相信突出显示的文本涵盖了您的示例。您没有问,但您可能有一个选择是在示例中使用两个模板参数。这两种情况都可以推断,因此您可以使用其他一些模板技巧,可能通过启用if来创建表示所需版本的新类型,即引用或者没有。

@Fionn-你能澄清你的答案吗?我知道你答对了:模板中的ret()函数和函数指针必须具有完全相同的签名。但是从你的响应文本来看,这并不明显。@Fionn,不,你错了。这用“int”而不是“int&”实例化了T我并没有要求“无错误地实例化代码”,而是要求“无引用地显式实例化代码,以便获得相同的输出”。谢谢。现在我明白你想做什么了。问题是没有明确的引用,编译器就不知道你是要按值传递还是按引用传递。如果要求它按引用传递,它只能按引用传递。为什么“int”和“int&”都可以推导出?没有任何函数声明“int”参数,而只是“int&”。即void ret(int&var){}。因此T只能是“int&”,否则ret(int&var)的签名将不适用于T。i.e ret(int-var)是不可能的。感谢您的响应。因此在我的示例中没有任何“P”和“A”集。只有P{是int&}。“A”正如我在之前的评论中所说的,这是不可能的。我认为这种歧义还有另一个原因,但我找不到:(在foo(k,ret)调用中:'int'是从'k->t'推导而来的,'int&'是从'ret'推导而来的,类型为'void(int&')->'void()(t')。你的P/A集是:{k,ret和P{t,void()(t)}.然后,根据标准文本,每对P/A推导出“T”,其结果不相同。
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);
#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;
}
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;
}