C++14 SFINAE 解引用迭代器

C++14 SFINAE 解引用迭代器

p { margin-bottom: 0.25cm; line-height: 120% }
a:link { }

原问题:编写函数f(r),若r为迭代器,则返回f(*r),否则返回r。

p { margin-bottom: 0.25cm; line-height: 120% }
a:link { }

摘要:

p { margin-bottom: 0.25cm; line-height: 120% }
a:link { }

问题:

  • 什么是迭代器?

    • 迭代器是c++中的一个概念,若类型It满足以下条件,则It为迭代器类型

      • 可拷贝构造(CopyConstructible)
      • 可拷贝赋值(CopyAssignable)
      • 可析构(Destructibale)
      • 左值It对象可交换(Swappable)
      • std::iterator_traits<It>含如下类型成员:value_type, difference_type, reference, pointer和iterator_category
      • 对于It的左值r,如下表达式合法且具有指定含义:
        • *r 返回值类型:unspecified 前置条件:r可解引用
        • ++r 返回值类型: It & 前置条件:r可自增

p { margin-bottom: 0.25cm; line-height: 120% }
a:link { }

在后续实现中,将放宽迭代器的要求:对左值r,设若*r合法,则r有迭代器类型。意即:

编写函数f(r),若左值r可被解引用,返回f(*r),否则返回r。

p { margin-bottom: 0.25cm; line-height: 120% }
a:link { }

问题分析:

f的返回值类型随实际参数而改变。若r为int **类型,至少需要两个f的重载int *f(int **)和 int f(int *)。需要通过泛型在编译期根据f的调用生成这些函数重载。

在调用时,重载决议阶段需要编译器选取合适的函数模板。

  • 若类型T的左值可被解引用,则选取函数模板(1)

    template <class T>
    auto f(T r) {
      return f(*r);
    }
  • 否则选取函数模板(2)

    template <class T>
    auto f(T r) {
      return r;
    }

问题:

  • 如何根据上述规则选取函数模板?

    • 若两个f模板均合法,则选取模板(1),否则选取合法模板。
    • 合法定义为:r可被解引用。

问题:

  • 如何表达优先选取?

    • 通过重载隐式转换序列分级。使得由模板(1)生成的函数的分级高于模板(2)
  • 如何表达合法性?

    • 通过SFINAE,若r不可被解引用,使得模板(1)替代失败(substitution failure)。

p { margin-bottom: 0.25cm; line-height: 120% }
a:link { }

实现:

 1 #include <cassert>
 2
 3 #include <type_traits>
 4 #include <utility>
 5
 6 template <class T>
 7 auto f(T x, ...) {
 8   return x;
 9 }
10
11 template <class T, class = decltype(*std::declval<T>())>
12 auto f(T x, int) {
13   return f(*x, 0);
14 }
15
16 int main() {
17   int x = 3, *p = &x;
18   assert(f(&p, 0)==3);
19
20   return 0;
21 }

p { margin-bottom: 0.25cm; line-height: 120% }
a:link { }

正文:

从略。

FAQ:

尚无。

参考资料:

http://en.cppreference.com/w/cpp/concept/Iterator

http://en.cppreference.com/w/cpp/language/overload_resolution (return type deduction)

http://en.cppreference.com/w/cpp/utility/declval

http://en.cppreference.com/w/cpp/language/overload_resolution

http://en.cppreference.com/w/cpp/language/template_argument_deduction

时间: 2024-10-27 02:20:16

C++14 SFINAE 解引用迭代器的相关文章

关于解引用*和箭头操作符-&gt;的重载

这里以一个智能指针类为例,智能指针所指为一个对象. 而事实上,STL迭代器的开发均需要重载这两个操作符,上一篇文章分析STL 迭代器中除了要用到template技巧外,还需要重载技巧 1 #include<iostream> 2 using namespace std; 3 class Screen 4 { 5 6 public: 7 friend ostream& operator<<(ostream&os, Screen &s); 8 int actio

操作符重载之解引用与箭头操作符

箭头操作符与众不同.它可能表现得像二元操作符一样:接受一个对象和一个成员名,对对象解引用以获取成员.不管外表如何,箭头操作符不接受显式形参.这里没有第二个形参,因为 -> 的右操作数不是表达式,相反,是对应着类成员的一个标识符.没有明显可行的途径将一个标识符作为形参传递给函数,相反,由编译器处理获取成员的工作. 理解1 当这样编写时:point->action();由于优先级规则,它实际等价于编写:(point->action)();换句话说,我们想要调用的是对 point->ac

解引用NULL指针

一般导致程序崩溃的最重要原因之一就是试图解引用NULL指针.正如上几篇文章中所说的,智能指针RefCountPtr和ScopedPtr提供了运行时的诊断.但是,并不是所有的指针都是拥有某个对象所有的智能指针.因此为了对试图解引用一个不具有对象所有权的指针的行为进行诊断,引入一种并不删除它所指向的对象的"半智能"指针.例如,如下代码示例: template <typename T> class Ptr { public: explicit Ptr(T* p = NULL) :

js 5.14 this的引用

5.14.1.this引用 的规则 在最外层的代码中,this引用的是全局对象 在函数内,this引用根据函数调用方式不同而有所不同 函数的调用方式this引用的引用对象 构造函数调用 所生成的对象 方法调用 接收方对象 apply或是call调用 有apply 或call的参数指定对象 其他的方式的调用 对象全局 通过点运算符或中括号运算符调用对象的方法时,在运算符左侧所指定对象下面方法和接受对象的具体例子var obj={ x:3, doit:function(){ console.log(

详解C# 迭代器

迭代器模式是设计模式中行为模式(behavioral pattern)的一个例子,他是一种简化对象间通讯的模式,也是一种非常容易理解和使用的模式.简单来说,迭代器模式使得你能够获取到序列中的所有元素而不用关心是其类型是array,list,linked list或者是其他什么序列结构.这一点使得能够非常高效的构建数据处理通道(data pipeline)--即数据能够进入处理通道,进行一系列的变换,或者过滤,然后得到结果.事实上,这正是LINQ的核心模式. 在.NET中,迭代器模式被IEnume

解引用

今天在c++ Primer 中文版 第五版 第二章 2.3.2看到解引用  下面是我的理解 1 int i = 42; 2 int &r = i;//&紧随类型名出现,因此是声明的一部分,r是一个引用 3 int *p;//*紧随类型名出现,因此是声明的一部分,p是一个指针 4 p = &i;//&出现在表达式中,是一个取地址符 5 *p = i;//*出现在表达式中,*是一个解引用符 6 int &r2 = *p;//*是一个解引用符 引用的本质是指针 给已经存在

顶点数组以及解引用单个数组

法线向量 物体的法线向量定义了他的表面在空间中的方向.具体地说定义了他相对于光源的方向.OpenGL使用法线向量确定了这个物体各个顶点所接受的光照.在定义物体的几何形状时,同时也定义了他的法线向量.可以使用glNormal*()函数,把当前法线向量设置为这个函数所标示的值,以后调用glVertex*()时,就会把当前法线向量分配给所指定的顶点.每个顶点尝尝具有不同的法线,所以需要交替调用这个函数. glBegin(GL_POLYGON); glNormal3fv(n0); glVertex3fv

关于C中指针的引用,解引用与脱去解引用

*,& 在指针操作中的意义 (1)* 大家都知道在写int *p 时,*可以声明一个指针.很少人知道*在C/C++中还有一个名字就是“解引用”.他的意思就是解释引用,说的通俗一点就是,直接去寻找指针所指的地址里面的内容,此内容可以是任何数据类型,当然也可以是指针(这就是双重指针,后面将会讨论).需要注意的是,在变量声明的时候,*不能当做解引用使用,只是表示你声明的变量是一个指针类型. example1: int a=50; int *p=&a;// '&'的作用就是把a变量在内存中

ArcGIS JavaScript api 4.14 离线部署引用

1. 下载 https://esrisoftware.esri.com/akdlm/software/ArcGIS_JavaScript/4.14/arcgis_js_v414_api.zip 官方地址 2. 部署 把下载的arcgis api 4.14 离线包解压拷贝到wwwroot目录下,在 4.14 文件夹之前的路径为 C:\inetpub\wwwroot\arcgis_js_v414_api\arcgis_js_api\library : C:\inetpub\wwwroot\arcgi