IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++待决名 -> 正文阅读

[C++知识库]C++待决名

模板类模板函数模板)定义中,某些构造的含义可以在不同的实例化间有所不同。特别是,类型和表达式可能会取决于类型模板形参的类型和非类型模板形参的值。

template<typename T>
struct X : B<T> // "B<T>" 取决于 T
{
    typename T::A* pa; // "T::A" 取决于 T
                       // (此 "typename" 的使用的目的见下文)
    void f(B<T>* pb)
    {
        static int i = B<T>::i; // "B<T>::i" 取决于 T
        pb->j++; // "pb->j" 取决于 T
    }
};

待决名和非待决名的名字查找和绑定有所不同。

绑定规则

非待决名在模板定义点查找并绑定。即使在模板实例化点有更好的匹配,也保持此绑定:

#include <iostream>
 
void g(double) { std::cout << "g(double)\n"; }
 
template<class T>
struct S
{
    void f() const
    {
        g(1); // "g" 是非待决名,现在绑定
    }
};
 
void g(int) { std::cout << "g(int)\n"; }
 
int main()
{
    g(1);  // 调用 g(int)
 
    S<int> s;
    s.f(); // 调用 g(double)
}

如果非待决名的含义在定义点和模板特化的实例化点间有所改变,那么程序非良构,不要求诊断。在下列情形可能会出现这种情况:

  • 非待决名用到的类型在定义点不完整但在实例化点完整
  • 模板定义中对名字的查找找到?using 声明,但实例化中对应作用域找不到任何声明,因为该 using 声明是包展开而对应的包为空
(C++17 起)
  • 实例化使用了在定义点尚未定义的默认实参或默认模板实参
  • 实例化点的某个常量表达式使用了整型或无作用域枚举类型的 const 对象的值、constexpr 对象的值、引用的值或者 constexpr 函数的定义?(C++11 起),而该对象/引用/函数?(C++11 起)在模板的定义点还没有定义
  • 该模板在实例化点使用了非待决的类模板特化或变量模板特化?(C++14 起),而它所用的这个模板,或者从某个在定义点处还没有定义的部分特化所实例化,或者指名了某个在定义点处还没有声明的显式特化。

待决名的绑定则延迟到查找发生时。

ADL查找规则等我们不再介绍

待决类型

下列类型是待决类型:

  • 模板形参
  • 未知特化(见下文)的成员
  • 作为未知特化(见下文)的待决成员的嵌套类/枚举
  • 待决类型的 cv 限定版本
  • 从待决类型构成的复合类型
  • 元素类型待决或边界(如果存在)是值待决的数组类型
  • 形参包含一个或多个函数形参包的函数类型
(C++11 起)
  • 异常说明是值待决的函数类型
  • 模板名是某个模板形参,或者
  • 有任何类型待决,或值待决,或者是包展开?(C++11 起)的模板实参(即使用到的模板标识不带实参列表,如注入类名
  • 应用到类型待决表达式的?decltype?的结果

应用到类型待决表达式的?decltype?的结果是唯一的待决类型。两个这样的结果只有在它们的表达式等价时才指代同一类型。

(C++11 起)

注意;当前实例化的 typedef 成员只有在它指代的类型待决时才会是待决的。

类型待决表达式?

下列表达式是类型待决的:

  • 含有类型待决的子表达式的表达式
  • this,如果它的类是待决类型
  • 不是概念标识的?(C++20 起)标识表达式,且
  • 包含某个能被自身的名字查找找到至少一个待决声明的标识符
  • 包含待决的模板标识
  • 包含特殊标识符?__func__(如果某个外围函数是模板,类模板的非模板成员,或泛型 lambda?(C++14 起))
(C++11 起)
  • 包含到某个待决类型的转换函数
  • 包含作为未知特化成员的嵌套名说明符或有限定标识
  • 指名当前实例化的某个待决成员,且该成员是“未知边界的数组”类型的静态数据成员
  • 包含某个能被自身的名字查找找到一个或更多的声明为具有返回类型推导的当前实例化的成员函数声明的标识符
(C++14 起)
  • 包含能被自身的名字查找找到一个初始化器为类型待决的结构化绑定声明的标识符
  • 包含能被自身的名字查找找到类型含占位符?auto?的非类型模板形参的标识符
  • 包含能被自身的名字查找找到以包含占位符类型的类型声明且初始化器是类型待决的变量(例如?auto?静态数据成员)的标识符,
(C++17 起)
  • 任何到待决类型的转型表达式
  • 创建待决类型对象的?new 表达式
  • 指代当前实例化的某个类型待决的成员的成员访问表达式
  • 指代未知特化的某个成员的成员访问表达式
(C++17 起)

注意:字面量、伪析构函数调用、alignofnoexcept?(C++11 起)、sizeoftypeiddelete、和?throw?表达式始终不是类型待决的,因为这些表达式的类型不可能待决。

?值待决表达式

(C++20 起)
  • 为类型待决的
  • 为某个非类型模板形参的名字
  • 指名某个作为当前实例化的待决成员的静态数据成员,且未被初始化。
  • 指名某个作为当前实例化的待决成员的静态成员函数
  • 为具有整数或枚举?(C++11 前)字面?(C++11 起)类型的常量,并从值待决表达式初始化
  • alignofnoexcept、?(C++11 起)sizeoftypeid?表达式,其实参是类型待决表达式或待决的类型标识
  • 任何向待决类型转换或从值待决表达式转换的转型表达式
  • 取址表达式,其实参是指名某个当前实例化的待决成员的有限定标识
  • 取址表达式,其实参是求值为核心常量表达式的,指代某个作为具有静态或线程?(C++11 起)存储期的对象或成员函数的模板化实体
(C++17 起)

?可以理解成只有实例化(单态化)后才能确定类型和/或求值方法的表达式。

???????

?待决名的?typename?消歧义符

在模板(包括别名模版)的声明或定义中,不是当前实例化的成员且取决于某个模板形参的名字不会被认为是类型,除非使用关键词?typename?或它已经被设立为类型名(例如用 typedef 声明或通过用作基类名)。

#include <iostream>
#include <vector>
 
int p = 1;
 
template<typename T>
void foo(const std::vector<T> &v)
{
    // std::vector<T>::const_iterator 是待决名,
    typename std::vector<T>::const_iterator it = v.begin();
 
    // 下列内容因为没有 'typename' 而会被解析成
    // 类型待决的成员变量 'const_iterator' 和某变量 'p' 的乘法。
    // 因为在此处有一个可见的全局 'p',所以此模板定义能编译。
    std::vector<T>::const_iterator* p; 
 
    typedef typename std::vector<T>::const_iterator iter_t;
    iter_t * p2; // iter_t 是待决名,但已知它是类型名
}
 
template<typename T>
struct S
{
    typedef int value_t; // 当前实例化的成员
 
    void f()
    {
        S<T>::value_t n{}; // S<T> 待决,但不需要 'typename'
        std::cout << n << '\n';
    }
};
 
int main()
{
    std::vector<int> v;
    foo(v); // 模板实例化失败:类型 std::vector<int> 中没有
            // 名字是 'const_iterator' 的成员变量
    S<int>().f();
}

关键词?typename?只能以这种方式用于限定名(例如?T::x)之前,但这些名字不必待决。

对前附?typename?的标识符使用通常的有限定名字查找。这与用详述类型说明符的情况不同,不管限定符如何都不改变查找规则:

struct A // A 拥有嵌套变量 X 和嵌套类型 struct X
{
    struct X {};
    int X;
};
 
struct B
{
    struct X {}; // B 拥有嵌套类型 struct X
};
 
template<class T>
void f(T t)
{
    typename T::X x;
}
 
void foo()
{
    A a;
    B b;
    f(b); // OK:实例化 f<B>,T::X 指代 B::X
    f(a); // 错误:不能实例化 f<A>:因为 A::X 的有限定名字查找找到了数据成员
}

待决名的?template?消歧义符

与此相似,模板定义中不是当前实例化的成员的待决名同样不被认为是模板名,除非使用消歧义关键词?template,或它已被设立为模板名:

template<typename T>
struct S
{
    template<typename U>
    void foo() {}
};
 
template<typename T>
void bar()
{
    S<T> s;
    s.foo<T>();          // 错误:< 被解析为小于运算符(但是MSVC可以正确解析,不符合标准)
    s.template foo<T>(); // OK
}

关键词?template?只能以这种方式用于运算符?::(作用域解析)、->(通过指针的成员访问)和?.(成员访问)之后,下列表达式都是合法示例:

  • T::template?foo<X>();
  • s.template?foo<X>();
  • this->template?foo<X>();
  • typename?T::template?iterator<int>::value_type?v;

与?typename?的情况一样,即使名字并非待决或它的使用并未在模板的作用域中出现,也允许使用?template?前缀。

即使?::?左侧的名字指代命名空间,也允许使用 template 消歧义符:

template<typename>
struct S {};
 
::template S<void> q; // 允许,但不需要

根据无限定名字查找针对成员访问表达式中的模板名的特殊规则,当非待决的模板名在成员访问表达式中出现时(->?或?.?后),如果通过表达式语境中的常规名字查找找到了的具有相同名字的类或别名?(C++11 起)模板,那么就不需要消歧义符。然而,如果表达式语境中的查找所找到的模板与类语境中所找到的不同,那么程序非良构。?(C++11 前)

template<int>
struct A { int value; };
?
template<class T>
void f(T t)
{
    t.A<0>::value; // A 的常规查找找到类模板。A<0>::value 指名类 A<0> 的成员
    // t.A < 0;    // 错误:'<' 被当做模板实参列表的起始
}

?总结:

以上全部代码和解释均来自cppreference,稍微有一些省略

待决名 - cppreference.comhttps://zh.cppreference.com/w/cpp/language/dependent_name

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-10-17 12:13:43  更:2022-10-17 12:17:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 3:42:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码