您现在的位置是:首页 >技术交流 >现代C++技术研究(2)---模板类型推导(2)网站首页技术交流

现代C++技术研究(2)---模板类型推导(2)

swordmanwk 2023-05-12 20:15:03
简介1)当ParamType是一个通用引用时,传入左值参数,模板的类型推导ParamType结果是左值引用,且ParamType和T相同,传入右值参数,模板的类型推导ParamType结果是右值引用,但ParamType和T是不同的,T去掉引用。可以看到,推导出的类型,T和ParamType是相同的,并且后面的const被去掉了,注意,前面的const属性是不能去掉的。可以看到,对于左值,T和ParamType类型相同,对于右值,T去引用,而ParamType是右值引用。

第二种情况:ParamType是一个通用引用(Universal Reference)

这种情况,模板类型推导的结果,就不那么直观了。看如下测试用例:

#include <iostream>
#include <type_traits>

template<typename T> void f(T&& param)
{
    using ParamType = T&&;
    bool TIsInt = std::is_same<T, int>::value;
    bool TIsConstInt = std::is_same<T, const int>::value;
    bool TIsIntRef = std::is_same<T, int&>::value;
    bool TIsConstIntRef = std::is_same<T, const int&>::value;
    if (TIsInt) {
        std::cout << "T is int, ";
    } else if (TIsConstInt) {
        std::cout << "T is const int, ";
    } else if (TIsIntRef) {
        std::cout << "T is int&, ";
    } else if (TIsConstIntRef) {
        std::cout << "T is const int&, ";
    } 
    bool ParamTypeIsIntRef = std::is_same<ParamType, int&>::value;
    bool ParamTypeIsConstIntRef = std::is_same<ParamType, const int&>::value;
    bool ParamTypeIsIntRefRef = std::is_same<ParamType, int&&>::value;
    if (ParamTypeIsIntRef) {
        std::cout << "param's type is int&
";
    } else if (ParamTypeIsConstIntRef) {
        std::cout << "param's type is const int&
";
    } else if (ParamTypeIsIntRefRef) {
        std::cout << "param's type is int&&
";
    }
}

int main()
{
    int x = 27; // x is an int
    const int cx = x; // cx is a const int
    const int& rx = x; // rx is a reference to x as a const int
    f(x);  // x is lvalue, so T is int&, param's type is int&
    f(cx); // cx is lvalue, so T is const int&, param's type is const int&
    f(rx); // rx is lvalue, so T is const int&, param's type is const int&
    f(27); // 27 is rvalue, so T is int, param's type is int&&
    return 0;
}

可以看到,对于左值,T和ParamType类型相同,对于右值,T去引用,而ParamType是右值引用。

第三种情况:ParamType既不是指针也不是引用

1)传入的参数是引用情况:

#include <iostream>
#include <type_traits>

template<typename T> void f(T param)
{
    using ParamType = T;
    bool TIsInt = std::is_same<T, int>::value;
    bool TIsConstInt = std::is_same<T, const int>::value;
    if (TIsInt) {
        std::cout << "T is int, ";
    } else if (TIsConstInt) {
        std::cout << "T is const int, ";
    }
    bool ParamTypeIsInt = std::is_same<ParamType, int>::value;
    bool ParamTypeIsConstInt = std::is_same<ParamType, const int>::value;
    if (ParamTypeIsInt) {
        std::cout << "param's type is int
";
    } else if (ParamTypeIsConstInt) {
        std::cout << "param's type is const int
";
    }
}

int main()
{
    int x = 27; // x is an int
    const int cx = x; // cx is a const int
    const int& rx = x; // rx is a reference to x as a const int
    f(x); // T is int, param's type is int
    f(cx); // T is int, param's type is int
    f(rx); // T is int, param's type is int
    return 0;
}

可以看到,推导出的类型,T和ParamType是相同的,并且const和引用都被去掉了。

2)传入的参数是指针的情况:

#include <iostream>
#include <type_traits>

using PtrType = const char* const;

template<typename T> void f(T param)
{
    using ParamType = T;
    bool TIsCstCharPoint = std::is_same<T, const char*>::value;
    bool TIsCstCharPointCst = std::is_same<T, const int* const>::value;
    if (TIsCstCharPoint) {
        std::cout << "T is const char*, ";
    } else if (TIsCstCharPointCst) {
        std::cout << "T is const char* const, ";
    }
    bool ParamTypeIsCstCharPoint = std::is_same<ParamType, const char*>::value;
    bool ParamTypeIsCstCharPointCst = std::is_same<ParamType, const int* const>::value;
    if (ParamTypeIsCstCharPoint) {
        std::cout << "param's type is const char*
";
    } else if (ParamTypeIsCstCharPointCst) {
        std::cout << "param's type is const char* const
";
    }
}

int main()
{
    const char* const ptr = "Fun with pointers"; // ptr is const pointer to const object
    f(ptr); // T is const char*, param's type is const char*
    return 0;
}

可以看到,推导出的类型,T和ParamType是相同的,并且后面的const被去掉了,注意,前面的const属性是不能去掉的。

小结:

1)当ParamType是一个通用引用时,传入左值参数,模板的类型推导ParamType结果是左值引用,且ParamType和T相同,传入右值参数,模板的类型推导ParamType结果是右值引用,但ParamType和T是不同的,T去掉引用。

2)当模板参数是值传递时,const和volatile等修饰都会被去掉,且ParamType和T相同。

参考资料:

《Effective Mordern C++》

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。