小编jba*_*bab的帖子

使用vs. typedef - 是否有一个微妙的,鲜为人知的区别?

背景

每个人都同意这一点

using <typedef-name> = <type>;
Run Code Online (Sandbox Code Playgroud)

相当于

typedef <type> <typedef-name>;
Run Code Online (Sandbox Code Playgroud)

并且前者因各种原因而优先于后者(参见Scott Meyers,Effective Modern C++和stackoverflow上的各种相关问题).

这是由[dcl.typedef]支持的:

也可以通过别名声明引入typedef-name.在使用关键字以下的标识符成为typedef名以及可选的以下标识符appertains到的typedef名称属性说明符-SEQ.这样的typedef-name具有与typedef说明符引入的语义相同的语义.

但是,请考虑诸如此类的声明

typedef struct {
    int val;
} A;
Run Code Online (Sandbox Code Playgroud)

对于这种情况,[dcl.typedef]指定:

如果typedef声明定义了一个未命名的类(或枚举),则声明声明为该类类型(或枚举类型)的第一个typedef-name用于表示仅用于链接目的的类类型(或枚举类型)(3.5 ).

参考部分3.5 [basic.link]说

如果名称是在typedef声明中定义的未命名类的名称,那么具有未在上面给出内部链接的命名空间范围的名称与封闭命名空间具有相同的链接,其中类具有用于链接的typedef名称用途[...]

假设上面的typedef声明是在全局命名空间中完成的,那么struct A将具有外部链接,因为全局命名空间具有外部链接.

现在的问题是,如果typedef声明被别名声明替换,根据它们是等效的常见概念,是否也是如此:

using A = struct {
    int val;
};
Run Code Online (Sandbox Code Playgroud)

特别是,A通过别名声明("using")声明的类型与通过typedef声明声明的类型具有相同的链接吗?

请注意,[decl.typedef]并未说别名声明 typedef声明(它只表示两者都引入了typedef-name),并且[decl.typedef]只说明了typedef声明(不是别名声明)为连接目的引入typedef名称的属性.如果别名声明是不能够进行联动的目的引入类型名字,A也只是一个匿名类型的别名,并没有任何联系的.

国际海事组织,这至少是对标准的一种可能的,尽管是严格的解释.当然,我可能会忽视某些事情.

这提出了随后的问题:

  • 如果确实存在这种微妙的差异,是通过意图还是标准中的疏忽?
  • 编译器/链接器的预期行为是什么?

研究

以下由三个文件组成的最小程序(我们至少需要两个独立的编译单元)用于调查该问题.

a.hpp

#ifndef A_HPP
#define A_HPP

#include <iosfwd>

#if USING_VS_TYPEDEF
using A = struct {
     int val;
}; …
Run Code Online (Sandbox Code Playgroud)

gcc language-lawyer c++11 clang++ c++14

23
推荐指数
1
解决办法
1427
查看次数

对于具有抛出复制构造函数和noexcept按值复制赋值的类,is_nothrow_copy_assignable的值是多少?

就C++标准而言,以下程序的预期(如果有)输出是什么:

#include <iostream>
#include <iomanip>
#include <type_traits>

class A {
public:
    A() = default;
    ~A() = default;
    A(A const& other) {}
    A(A&& other) noexcept {}
    A& operator=(A other) noexcept { return *this; }
};

int main() {
    std::cout << std::boolalpha
        << std::is_nothrow_copy_assignable<A>::value << "\n"
        << std::is_nothrow_move_assignable<A>::value << "\n";
}
Run Code Online (Sandbox Code Playgroud)

换句话说,类型特征值的评估是仅仅查看赋值运算符的声明,这是noexcept,并且它因此产生

true
true
Run Code Online (Sandbox Code Playgroud)

或者它是否考虑调用上下文(a,b是实例A)

a = b;            // may throw, implicitly calls copy c'tor
a = std::move(b); // noexcept, implicitly calls move c'tor
Run Code Online (Sandbox Code Playgroud)

它会屈服吗?

false …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer c++11 c++14

5
推荐指数
1
解决办法
160
查看次数

标签 统计

c++11 ×2

c++14 ×2

language-lawyer ×2

c++ ×1

clang++ ×1

gcc ×1