首页 > 编程语言 >c++ 模板参数有默认值时模板特例化匹配问题

c++ 模板参数有默认值时模板特例化匹配问题

时间:2022-12-24 18:13:19浏览次数:51  
标签:enable struct void c++ template 默认值 模板 特化

如下的源码:

template<typename T, typename U = int>
class S{ //#1
  public:
    void f1(){};
};

template<>
class S<void> {		//#2
  public:
    void f2(){};
};

int main()
{
  S<void, int> sv;	// OK: uses #2, definition available  #3
  //sv.f1();//error
  sv.f2();//ok
}

clang模板展开时,#3变成:

 S<void> sv = S<void>();

为啥S<void, int> 不走主模板分支 #1?

其实 #2 的实现,S<void> 就是 S<void,int>。

实现过程:

class S<void> 的实例化,查找到前面有主模板定义:

template<typename T, typename U = int> class S

因为第二个模板参数默认值是int所以 会自动生成

S<void, int>

也就是说,class S<void> 根据主模板,就是 S<void, int>。

接下来就是 S<void, int> 选择哪个匹配问题。根据模板匹配找最适合的,范围更小的。最终选定偏特化的,主模板的范围太广了。

再看一个小的示例:

//这个是主模板
template<bool, typename T= void> //这个T,可以省略,因为没有被引用
struct en_if {};

//一个偏特化模板。之所以不是全特化,还保留了主模板的第二个参数
template< typename T>
struct en_if <true, T> { using TYPE = T; };

/////------
en_if<true>::TYPE* a;

en_if<true>,这个根据主模板,形成: en_if<true, void>。(会去主模板,没提供 T,默认是void,最终 T就变成了 void)。

接下来 en_if<true, void>选择主模板,还是偏特化的问题。

主模板:template<bool,typename T=void>

偏特化:en_if<true, T>

偏特化更符合,范围更小。即符合偏特化,肯定符合主模板;符合主模板,不一定符合偏特化。

偏特化被改的话,都会报错:

//一个偏特化模板。之所以不是全特化,还保留了主模板的第二个参数
template< typename T=void>
struct en_if <true, T> { using TYPE = T; };

//一个偏特化模板。之所以不是全特化,还保留了主模板的第二个参数
template< typename T=int>
struct en_if <true, T> { using TYPE = T; };

上面两种修改都会导致报错:

error: default template argument in a class template partial specialization
template< typename T=void>
^
1 error generated.
 

实际应用

通过默认模板参数 来选择默认的特化版本,当条件不成立时,退回到主模板。
  • 当默认模板参数是类型,则一般为void,并在特化版本通过void_t或者 enable_if_t选择;
  • 若为值,则用bool常量表达式结果作为默认参数并在特化版本中通过true false选择。

以上摘自《c++20高级编程》罗能 p64.

enable_if 作为约束使用,它虽然出现在模板上的一个参数,但是没有用,只是作为模板模式匹配用途。在c++20用约束来替换。

1, 关于默认值的模式匹配

template<bool B, class T=long>
struct enable_if{};

template<class T>
struct enable_if<true,T>{
  using type = T;
};

enable_if<true>::type a;

可以看到,a是个 long 类型。

template<bool B, class T = long>
struct enable_if
{
};

/* First instantiated from: insights.cpp:9 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
struct enable_if<true, long>
{
  using type = long;
};

#endif


template<class T>
struct enable_if<true, T>
{
  using type = T;
};

enable_if<true>::type a;

 2,它真正用途是作为 选择器。上面的long其实没用,用void代替。

#include <iostream>

template<bool B, class T=void>
struct enable_if{};

template<class T>
struct enable_if<true,T>{
  using type = T;
};

template<class T, class U=typename enable_if< std::is_integral_v<T> >::type >
struct X{
};

X<int> ok;
X<std::string> compile_failed;

由于enable_if<false> 会匹配主模板定义,而里面是没有 type 这个定义的。所以导致 compile_failed。

可以看到上面的 class U模板参数只是作为约束存在,没有任何实际意义。c++20用 concept。

#include <iostream>

template<class T>
  concept IntType= std::is_integral_v<T>;


template<IntType T>
struct X{
};

X<int> ok;
//X<std::string> compile_failed;

进一步可以简化为:

template<class T>
requires std::is_integral_v<T>
struct X{
};

X<int> ok;

 

标签:enable,struct,void,c++,template,默认值,模板,特化
From: https://www.cnblogs.com/bigben0123/p/16919311.html

相关文章

  • 蓝桥-13届-C++-B组-省赛-F题-统计子矩阵
    直达链接主要解题思路分为两个部分,1是构造二维前缀和计算矩阵和,降低每次求和的时间复杂度;2是对所有子矩阵的遍历求和过程,因为需要两个坐标,遍历4个行/列值,4层for循环时间复......
  • C++基础3
    C++基础3typedef为现有类型创建一个新名字主要有以下几种形式:为基本数据类型定义别名为指针定义别名为自定义数据类型定义别名为数组定义别名声明函数定义新......
  • 1004.Django模板标签
    一、常用标签模板标签标签在渲染的过程中提供任意的逻辑。这个定义是刻意模糊的。例如,一个标签可以输出内容,作为控制结构,例如“if”语句或“for”循环从数据库中提取内......
  • C/C++编译器配置——MinGW下载安装
    C/C++编译器配置——MinGW下载安装前言本文主要讲述如何安装C语言编译器——MinGW,特点是文章附有完整详细的实际安装过程截图,文字反而起说明提示作用。编写本文的原因......
  • 国产paozhu c++ web framework 正式版发布
    经过大半个月测试修改paozhuc++webframework正式版发布,1.0.5release官方第一次发布正式版,可以用于生产环境。易用性超越国外各种c++webframework,简单易用,新手......
  • C++11:返回值类型后置(跟踪返回值类型)
    返回值类型后置语法,是为了解决函数返回值类型依赖于参数而导致难以确定返回值类型的问题。有了这种语法以后,对返回值类型的推导就可以用清晰的方式(直接通过参数做运算)描述......
  • C++进阶(哈希)
    vector容器补充(下面会用到)我们都知道vector容器不同于数组,能够进行动态扩容,其底层原理:所谓动态扩容,并不是在原空间之后接续新空间,因为无法保证原空间之后尚有可配置的空间......
  • C++——贪心
     5745:演讲大厅安排描述有一个演讲大厅需要我们管理,演讲者们事先定好了需要演讲的起始时间和中止时间。我们想让演讲大厅得到最大可能的使用。我们要接受一些预定而拒......
  • 模板
    模板#include<bits/stdc++.h>#definefifirst#definesesecond#definempmake_pair#definepbpush_back#defineebemplace_backtypedeflonglongll;using......
  • C++读写文本文件
    std::stringreadText(std::string&filename){std::stringshaderCodeStr("");std::ifstreamshaderFile;shaderFile.exceptions(std::ifstream::failb......