模板参数推导如何区分左值和字面量/编译时值
How does template argument deduction distinguish between an lvalue and a literal/compile-time value
这是一个关于OP对constexpr对重载有用的解决方案的问题。
基本上,他用了
template<class T>
typename std::enable_if<std::is_arithmetic<T>::value, int>::type
f(T&& n) { ... }
和
template<class T>
typename std::enable_if<!std::is_arithmetic<T>::value, int>::type
f(T&& n) { ... }
知道调用f()
时是否使用一个编译时变量(如:literal: f(42)
)或一个左值(如:局部变量:f(argc)
)作为参数。
std::is_arithmetic<T>::value == true
)下面是一个完整的例子:
Run It Online
#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;
}
表单
的模板函数template <typename T>
void func(T&& t);
看起来好像接受了一个r值引用。但实际上T&&
这里是Scott Meyers所说的通用引用,或者称为转发引用。根据参数的值类别不同会发生不同的事情。让我们看一下每一种情况:
t是非const左值,例如
int i = 0; func(i);
在本例中,T被推导为对
int
的左值引用,即T=int&
。t是const左值,例如
const int i = 1; func(i);
同样,在这种情况下,
T
被推断为const int&
。t为右值,例如
func(1);
在这种情况下,
T
被推断为int
,正如我们可能期望的那样
为什么这些演绎会以这种方式发生,与引用坍缩的规则有关;如果你感兴趣的话,我强烈推荐你阅读Scott Meyers关于这个主题的文章。
上面的最后一个例子也说明了在C和c++中,字面值(字符串字面值除外)总是右值。
这和enable_if
有什么关系?如果你的f
是用一个整数字面值调用的,那么T
就会被推断为普通的int
。显然,is_arithmetic<int>
为真,因此第二个函数得到SFINAE输出,并调用第一个函数。
但是,当带左值调用时,T
被推导为(const) int&
。引用是而不是算术,因此第一个函数消失,只剩下第二个函数要调用。
相关文章:
- 非类型指针和引用模板参数,以及在编译时如何/为什么解析它们.c++
- 根据编译时参数在 C 中重复代码
- 使用 SFINAE 作为模板参数的编译时递归
- 使用带有 ref 参数的成员函数创建线程时出现编译错误
- 使用 std::enable_if 限制派生类的模板参数时出现编译错误
- 带有自动参数的函数使用 GCC 编译,但不使用 Visual C++ 编译
- 为什么我的递归可变参数模板无法编译?
- 知道模板参数在编译时是否为 const char*?
- 可变参数模板未在 MSVC 中编译?
- 将函数类型作为模板参数传递不会编译
- 线程构造函数周围的可变参数模板包装器无法编译
- 编译错误:临时对象构造函数中缺少参数
- 在编译时收集模板参数
- 有没有办法根据命令行参数定义数组大小?运行时与编译时实例化?
- C++模板-基于参数编译成员函数
- C++编译时检查是否可以用某种类型的参数调用重载函数
- Visual Studio代码:C 编译参数-O
- Clang 无法使用模板元编程编译参数包扩展
- 如何更改和设置Rcpp编译参数
- Jamfile的可移植编译参数