简体   繁体   English

C ++模板在不使用'&'的情况下无法推断出引用类型

[英]C++ Templates can't deduce Reference Types without using '&'

Here's a very simple example: 这是一个非常简单的示例:

#include <iostream>

template<typename T>
void DoubleMe(T x) {
    x += x;
}

int main()
{
    int a = 10;
    DoubleMe(a);
    std::cout << a; //displays 10 not 20!
}

In cases like this, am I forced to use 'T&' in the function argument instead? 在这种情况下,我是否必须在函数参数中使用“ T&”代替? Cuz I have read in some tutorials that templates can correctly deduce the appropriate data type, including T*, T[ ], or T& by just defining a simple 'T' before the variable. 因为我在一些教程中已经读到模板可以通过在变量之前定义一个简单的“ T”来正确推断出适当的数据类型,包括T *,T []或T&。 Help? 救命?

Yes, to get the effect you want here, you must add the ampersand. 是的,要在此处获得所需的效果,必须添加&符。

As you write, templates can correctly deduce data types. 在编写时,模板可以正确推断数据类型。 However, they cann deduce intent. 但是,他们无法推断意图。 In this case, the type you pass it is an integer, and it correctly instantiates an integer function that internally doubles the argument passed to it by value. 在这种情况下,您传递的类型是整数,并且它正确地实例化了一个整数函数,该函数在内部将按值传递给它的参数加倍。 The fact that you meant the function to have a side effect, is not something the compiler can guess. 意思是该函数具有副作用,这一事实并不是编译器可以猜测的。

You can indeed correctly deduce reference types with plain T . 您确实可以使用普通T正确推断引用类型。 Unfortunately, that does not mean what you think it means. 不幸的是,这并不意味着您认为的意思。

Given 给定

template <typename T> struct S { };
template <typename T> void f(S<T>) { }
int main() { f(S<int&>{}); }

the type argument for f is correctly deduced as int& . f的类型参数正确推导为int&

The problem is that in your case, deducing T as int produces a perfectly valid function already. 问题是,在您的情况下,将T推导出为int已经产生了一个完全有效的函数。 Perhaps a slight oversimplification, but type deduction produces the simplest T that makes the call work. 也许稍微简化了一下,但是类型推导产生了使调用正常工作的最简单的T In your case, T = int makes the call work. 在您的情况下, T = int使调用起作用。 Not the way you want it to work, but the compiler can't know that. 不是您希望它工作的方式,但是编译器无法知道。 T = int & would also make the call work, but it's not the simplest T that makes it work. T = int &也可以使调用正常工作,但这不是使它正常工作的最简单的T

Maybe this will help you to see it the way the compiler does (apologies to any language lawyers if I am oversimplifying): 也许这将帮助您以编译器的方式查看它(如果我过于简化的话,请向任何语言律师致歉):

In this example, the compiler must infer the type of T to be the type that makes the function declaration legal with the least amount of deduction. 在此示例中,编译器必须将T的类型推断为以最小的推导量使函数声明合法的类型。 Since a T can usually be copy-constructed directly from a const T& (which implies that it can also be copy-constructed from a T&), your function will take a copy. 由于通常可以直接从const T&复制构造T(这意味着它也可以从T&复制构造),因此您的函数将复制一个副本。

template<class T>
void foo(T value); 

In this example T must be the type of the object thing ref refers to - and since references cannot refer to references, T must be a (possibly const, possibly volatile) type. 在此示例中,T必须是ref引用的对象的类型-并且由于引用不能引用引用,因此T必须是(可能是const,可能是易失的)类型。

template<class T>
void foo(T& ref);

In this example, ref must be referring to a const (possibly volatile) object of type T: 在此示例中,ref必须引用类型T的const(可能是volatile)对象:

template<class T>
void foo(const T& ref);

In this example, ref may either be a reference or an r-value reference. 在此示例中, ref可以参考 r值参考。 It's known as a universal reference. 它被称为通用参考。 You're actually writing two functions in one and it's often the most efficient way to handle the case where you are taking ownership of ref . 实际上,您实际上是在编写两个函数,这通常是处理拥有ref所有权的情况的最有效方法。

template<class T>
void foo(T&& ref);

// called like this:
foo(Bar());   // means ref will be a Bar&&

// called like this:
Bar b;
foo(b);       // means ref will be a Bar&

// called like this:
const Bar b;
foo(b);       // means ref will be a const Bar&

In summary: 综上所述:

void foo(T value) means I will make a copy of whatever you give me. void foo(T value)表示我复制您给我的任何内容。

void foo(T& value) means I wont make a copy but I may modify your value. void foo(T& value)表示我不会复制,但我可以修改您的值。 You may not give me a temporary . 你可能不会给我临时的

void foo(const T& value) means I wont make a copy and I cannot modify your copy. void foo(const T& value)意味着我不会进行复制,并且无法修改您的副本。 You may give me a temporary. 你可以给我临时的。

void foo(const T&& value) means I may steal or modify the contents of your value, even if it's a temporary . void foo(const T&& value)意味着我可以窃取或修改您的值的内容, 即使它是临时的

If you want the function to pass the argument by value, you need to return the value with the same argument type. 如果希望函数按值传递参数,则需要返回具有相同参数类型的值。

T DoubleMe(T x) {
     return x + x;
 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM