模板参数推导如何区分左值和文字/编译时值

时间:2015-10-18 10:51:17

标签: c++ c++11 template-meta-programming overloading overload-resolution

这是与OP的Is constexpr useful for overload解决方案相关的问题。

基本上,他用过

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()是一个编译时变量(例如文字:f(42))或左值(例如局部变量:f(argc))作为其参数。< / p>

问:这是如何工作的? (我预计,在两次调用中,都会调用第一个重载(即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;
}

1 个答案:

答案 0 :(得分:1)

表格

的模板功能
template <typename T>
void func(T&& t);

看起来像,好像它需要一个r值引用。但实际上T&&这里是Scott Meyers所谓的通用引用,也称为转发引用。根据参数的值类别,可能会发生不同的事情。让我们来看看每个案例:

  1. t是非常数左值,例如

    int i = 0;
    func(i);
    

    在这种情况下,T被推断为int的左值引用,即T=int&

  2. t是一个const值,例如

    const int i = 1;
    func(i);
    

    同样,在这种情况下,T推断为const int&

  3. t是一个右值,例如

    func(1);
    

    在这种情况下,T被推断为int正如我们预期的那样

  4. 究竟为什么这些推论以这种方式发生,与参考折叠的规则有关;我强烈推荐阅读Scott Meyers&#39;如果您有兴趣,请参阅有关该主题的文章。

    上面的最后一个案例也说明了在C和C ++中,文字(字符串文字除外)总是rvalues。

    这与enable_if有什么关系?如果您使用整数文字调用f,那么T推断为普通int。显然,is_arithmetic<int>是正确的,所以第二个函数得到SFINAE并且第一个被调用。第一个被调用。

    然而,当使用左值调用时,T被推断为(const) int&。引用是 not 算术,因此第一个函数消失,只留下第二个函数被调用。