[英]How does template argument deduction distinguish between an lvalue and a literal/compile-time value
This is a question related to OP's solution to Is constexpr useful for overload . 这是与OP的constexpr对重载有用的解决方案有关的问题。
Basically, he used 基本上,他用
template<class T>
typename std::enable_if<std::is_arithmetic<T>::value, int>::type
f(T&& n) { ... }
and 和
template<class T>
typename std::enable_if<!std::is_arithmetic<T>::value, int>::type
f(T&& n) { ... }
to know whether f()
has been called with is a compile-time variable (eg literal: f(42)
) or an lvalue (eg local variable: f(argc)
) as its argument. 知道是否已使用
f()
调用了编译时变量(例如,文字: f(42)
)还是左值(例如,局部变量: f(argc)
)作为其参数。
Q: How does that work ? 问:如何运作? (I expected, in both calls, that the first overload would be called (ie
std::is_arithmetic<T>::value == true
) (我希望在两个调用中都将调用第一个重载(即
std::is_arithmetic<T>::value == true
))
Here is a full example: 这是一个完整的示例:
#include <iostream>
#include <type_traits>
using std::cout;
using std::endl;
template<class T>
constexpr
typename std::enable_if<std::is_arithmetic<T>::value,
int>::type
inline f(T&& n)
{
//cout << "compile time" << endl;
return 1;
}
template<class T>
typename std::enable_if<!std::is_arithmetic<T>::value,
int>::type
inline f(T&& n)
{
//cout << "run time" << endl;
return 0;
}
int main(int argc, char* argv[])
{
const int rt = f(argc);
constexpr int ct = f(42);
cout << "rt: " << rt << endl;
cout << "ct: " << ct << endl;
}
A template function of the form 表单的模板功能
template <typename T>
void func(T&& t);
looks as if it takes an r-value reference. 看起来好像需要一个r值参考。 But in actual fact
T&&
here is what Scott Meyers calls a universal reference , otherwise known as a forwarding reference. 但是实际上,
T&&
这就是Scott Meyers所谓的通用引用 ,也称为转发引用。 Different things can happen depending on the value category of the argument. 根据参数的值类别,可能发生不同的事情。 Let's have a look at each case:
让我们看一下每种情况:
t is a non-const lvalue, for example t是非常量左值,例如
int i = 0; func(i);
In this case, T is deduced to be an lvalue reference to int
, that is, T=int&
. 在这种情况下,T被推导为
int
的左值引用,即T=int&
。
t is a const lvalue, for example t是一个常量左值,例如
const int i = 1; func(i);
Similarly, in this case T
is deduced to be const int&
. 类似地,在这种情况下,
T
被推导为const int&
。
t is an rvalue, for example t是一个右值,例如
func(1);
In this case, T
is deduced to be int
just as we might have expected 在这种情况下,正如我们可能预期的那样,推导
T
为int
Exactly why these deductions happen this way is to do with the rules for reference collapsing; 这些推论之所以如此发生,恰恰与参考折叠的规则有关。 I highly recommend reading Scott Meyers' article on the subject if you're interested.
如果您有兴趣,我强烈建议阅读Scott Meyers关于该主题的文章。
The last case above also illustrates the point that in C and C++, literals (except string literals) are always rvalues. 上面的最后一种情况还说明了一点,在C和C ++中,文字(字符串文字除外)始终是右值。
What does this have to do with the enable_if
? 这与
enable_if
什么关系? Well if your f
is called with an integer literal, then T
is deduced to be plain int
. 好吧,如果您的
f
用整数字面量调用,则T
被推导为纯int
。 Obviously, is_arithmetic<int>
is true, so the second function gets SFINAE'd out and the first is called. 显然,
is_arithmetic<int>
为true,因此第二个函数被SFINAE退出,第一个函数被调用。
However, when called with an lvalue, T
is deduced to be (const) int&
. 但是,当用左值调用时,
T
推导为(const) int&
。 A reference is not arithmetic, so the first function disappears leaving only the second to be called. 引用不是算术运算,因此第一个函数消失了,仅剩下第二个函数要调用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.