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

标签 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))作为其参数。

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

看起来 好像它采用右值引用。但实际上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正如我们所预料的那样

这些推导以这种方式发生的确切原因与引用折叠规则有关;如果您有兴趣,我强烈建议您阅读 Scott Meyers 关于该主题的文章。

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

这与 enable_if 有什么关系? ?好吧,如果你的 f用整数文字调用,然后是T推导为普通 int .显然,is_arithmetic<int>是真的,所以第二个函数得到 SFINAE'd 并调用第一个函数。

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

关于c++ - 模板参数推导如何区分左值和文字/编译时值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33197073/

相关文章:

c++ - lambda 的捕获变量被重置

C++ u8 literal char 覆盖

c++ - 在专用线程中清除 STL

c++ - 为什么 implicit == on map<<int,MyClass> 不编译?

C++:我正在做的事情的名称和联系?

c++ - 这段代码中的delete[] free 是否正确?

c++11 - 错误 : <atomic> is not implemented in LLVM version 5. 1

c++ - 获取可变模板参数的尾部

template-meta-programming - 通过乘法生成一个查找表来除以 10 位整数

c# - 使用 CodeMemberMethod 创建异步方法