C++ 模板函数返回值"重载"

C++ 模板函数返回值"重载"

  • 不想看梳理过程的看这里
  • 1 简析(真实应用在3.1,不想看那些梳理的直接跳过去)
    • 1.1 问题产生原因
    • 1.2 突破口 C++11特性
  • 2 解决利器
    • 2.1 SFINAE
    • 2.2 std::enable_if
            • 2.2.1 头文件
            • 2.2.2 原理
            • 2.2.3 范例
            • 2.2.4 用法解析
    • 2.3 std::is_same
            • 2.3.1 头文件
            • 2.3.2 范例
            • 2.3.3 用法解析
  • 3 解决方案(不想看梳理过程的直接看这节)
    • 3.1 关键代码部分
  • 4 写在最后

不想看梳理过程的看这里

传送门

1 简析(真实应用在3.1,不想看那些梳理的直接跳过去)

1.1 问题产生原因

在正常C++语言应用中,函数重载需要保证重载函数的返回值不变,改变函数的入参参数列表,而模板函数通常可以更加完美地实现更灵活的入参参数定义,达到泛型编程的目的,正常情况下,由于模板函数是在编译时未进入函数时进行的函数推导,推导在函数内条件判断之前,因此如果在正常函数内进行的条件判断来确定返回值时,会产生编译错误,由模板函数推导后的函数只能return一种返回值类型,从而导致模板函数难以进行类似重载的操作。

1.2 突破口 C++11特性

C++ 11 可以利用SFINAE根据类型特征有条件地从重载决策中删除函数。

2 解决利器

2.1 SFINAE

SFINAE在CppReference上的链接

SFINAE全称是"Substitution Failure Is Not An Error",即“替换失败不是错误”

在函数模板的重载决议中应用此规则:当将模板形参替换为显式指定的类型或推导的类型失败时,从重载集中丢弃这个特化,而非导致编译失败。
此特性被用于模板元编程。

2.2 std::enable_if

2.2.1 头文件
#include 
2.2.2 原理

此元函数是活用 SFINAE ,基于类型特性条件性地从重载决议移除函数,并对不同类型特性提供分离的函数重载与特化的便利方法。
std::enable_if 可用作额外的函数参数(不可应用于运算符重载)、返回类型(不可应用于构造函数与析构函数),或类模板或函数模板形参。

2.2.3 范例

引用自CppReference
错误方法

struct T {
    enum { int_t,float_t } m_type;
    template <typename Integer,
              typename = std::enable_if_t<std::is_integral_v<Integer>>
    >
    T(Integer) : m_type(int_t) {}
 
    template <typename Floating,
              typename = std::enable_if_t<std::is_floating_point_v<Floating>e>
    >
    T(Floating) : m_type(float_t) {} // error: cannot overload
};

正确方法

struct T {
    enum { int_t,float_t } m_type;
    template <typename Integer,
              std::enable_if_t<std::is_integral_v<Integer>, int> = 0
    >
    T(Integer) : m_type(int_t) {}
 
    template <typename Floating,
              std::enable_if_t<std::is_floating_point_v<Floating>, int> = 0
    >
    T(Floating) : m_type(float_t) {} // OK
};
2.2.4 用法解析
auto typeName = std::enable_if<[bool],[typename]>::type
  • 在bool条件为true的情况下,typeName 为 typename类型名
  • 在bool条件为false的情况下,typeName不存在

2.3 std::is_same

2.3.1 头文件
#include 
2.3.2 范例

不引用了,心累

2.3.3 用法解析
auto is_same_v = is_same<[type1], [type2]>::value
  • type1类型与type2类型相同时返回is_same_v为true
  • type1类型与type2类型不同时返回is_same_v为false

3 解决方案(不想看梳理过程的直接看这节)

3.1 关键代码部分

  1. 模板定义
#include 
#include 
template <class T> 
typename std::enable_if<std::is_same<T,std::string>::value,T>::type foo()
{
	return "This is std::string";
}
template <class T> 
typename std::enable_if<std::is_same<T, int>::value, T>::type foo()
{
	return 1;
}
  1. 应用
std::string retString = foo<std::string>();
int retInteger = foo<int>();
  1. 结果
retString = "This is std::string";
retInteger = 1;

4 写在最后

平时不怎么爱写Blog,基本就是在写代码,虽然写的很烂;下半年考研,估计要丢下一阵子代码去复习了,突然感觉很惶恐,最近全天不休的写代码,希望能够有所收获。

你可能感兴趣的:(c-c++,模板,C++11)