以下の内容はhttps://yohhoy.hatenadiary.jp/より取得しました。


冗長なtypenameキーワード

プログラミング言語C++において型(type)名を記述するとき、C++11以降では修飾名(qualified name)に限って冗長なtypenameキーワードを記述しても良い。

#include <cstddef>
using std::size_t;
struct S { using type = int; };

typename int x0;     // NG
typename size_t n0;  // NG

typename std::size_t n1;  // OK
typename ::size_t n2;     // OK
typename S::type v1;      // OK

C++03時点ではtypenameキーワードの明記はテンプレート定義内に限定されていたが、Core Working Group Issue#382により修正された経緯がある。同Issueより一部引用(下線部は強調)。

P. J. Plauger, among others, has noted that typename is hard to use, because in a given context it's either required or forbidden, and it's often hard to tell which. It would make life easier for programmers if typename could be allowed in places where it is not required, e.g., outside of templates

Notes from the April 2003 meeting:
There was unanimity on relaxing this requirement on typename. The question was how much to relax it. Everyone agreed on allowing it on all qualified names, which is an easy fix (no syntax change required). But should it be allowed other places? P. J. Plauger said he'd like to see it allowed anywhere a type name is allowed, and that it could actually be a decades-late assist for the infamous "the ice is thin here" typedef problem noted in K&R I.

Notes from October 2003 meeting:
We considered whether typename should be allowed in more places, and decided we only wanted to allow it in qualified names (for now at least).

おまけ:CWG 382で言及される “typedef problem” に関して、K&R C 1st Ed., §11.1 Lexical scopeより言及箇所を引用する。C言語では「変数名のない空の宣言*1」が許容されることと、「型名省略時の暗黙int宣言」はC99で削除されたため、現在からみると意図を読み取りづらい。

In all cases, however, if an identifier is explicitly declared at the head of a block, including the block constituting a function, any declaration of that identifier outside the block is suspended until the end of the block.

Remember also (§8.5) that identifiers associated with ordinary variables on the one hand and those associated with structure and union members and tags on the other form two disjoint classes which do not conflict. Members and tags follow the same scope rules as other identifiers. typedef names are in the same class as ordinary identifiers. They may be redeclared in inner blocks, but an explicit type must be given in the inner declaration:

typedef float distance;
...
{
    auto int distance;
    ...

The int must be present in the second declaration, or it would be taken to be a declaration with no declarators and type distance.

脚注† lt is agreed that the ice is thin here.

関連URL

*1:GCCでは警告"useless type name in empty declaration"、Clangでは警告"declaration does not declare anything"として検知される。

型パックからのインデクス指定

プログラミング言語C++において、テンプレートパラメータパック(template parameter pack)からインデクス指定で型(type)を選択する方法。C++2c(C++26)以降では直接的な記述が可能となる。

#include <tuple>

// C++11
template <std::size_t Idx, typename... Ts>
using Selector = typename std::tuple_element<Idx, std::tuple<Ts...>>::type;

// C++14
template <std::size_t Idx, typename... Ts>
using Selector = std::tuple_element_t<Idx, std::tuple<Ts...>>;

// C++2c(C++26)
template <std::size_t Idx, typename... Ts>
using Selector = Ts...[Idx];

// Selector<0, char, int, float> == char
// Selector<1, char, int, float> == int
// Selector<2, char, int, float> == float

関連URL

unitbufマニピュレータ

C++標準ライブラリのI/Oストリームにおける知名度の低いマニピュレータ(manipulator)。*1

出力ストリームに対して出力操作毎のフラッシュ(flush)を指示する。*2

#include <iostream>

int x = 42;
std::cout << std::unitbuf;

std::cout << "x=" << x << "\n";
// operator<<呼び出し毎にflushされる

標準エラーストリームstd::cerrは初期状態でstd::ios_base::unitbufフラグがセットされている。*3

C++03 27.3.1/p3-4, 27.4, 27.4.2.1.2/Table 83, 27.4.5.1/p25-26, 27.6.2.3/p4, 27.6.2.5.1/p1より一部引用。

ostream cerr;

4 The object cerr controls output to a stream buffer associated with the object stderr, declared in <cstdio> (27.8.2).
5 After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for basic_ios<char>::init (27.4.4.1).

#include <iosfwd>
namespace std {
  // 27.4.5, manipulators:
  // (snip)
  ios_base& unitbuf  (ios_base& str);
  ios_base& nounitbuf(ios_base& str);
  // (snip)
}

Table 83 - fmtflags effects

Element Effect(s) if set
unitbuf flushes output after each output operation;
ios_base& unitbuf(ios_base& str);

25 Effects: Calls str.setf(ios_base::unitbuf).
26 Returns: str.

˜sentry();

4 If ((os.flags() & ios_base::unitbuf) && !uncaught_exception()) is true, calls os.flush().

1 Each formatted output function begins execution by constructing an object of class sentry. (snip)

関連URL

*1:当社比:https://x.com/yohhoy/status/2011376066376696061

*2:ライブラリ仕様上は basic_ostream::sentry クラスのデストラクタでフラッシュ操作が規定される。出力関数の開始時に同クラスオブジェクトを作成し、終了時にデストラクタが呼び出される。

*3:ワイド文字標準エラーストリーム std::wcerr も同様に、初期状態で unitbuf フラグが設定される。

"obsolescent feature" in 標準C

プログラミング言語C標準規格に登場する「廃止予定の機能(obsolescent feature)」の意味を正確に規定する提案が提出されている。

Motivation
Mixing the terms "obsolete", "obsolescent", "deprecated", and "removed", despite distinctions in their meanings, sends confusing and inconsistent message to the outside world, leading to misunderstandings even among the members of the Committee.

This paper aims to clarify the terminology by defining term "obsolete" and the categories of such state.

The Standard itself ought to use the precise categories for individual features. The word "obsolete" is an umbrella term, already seen as existing practice in community (see: cppreference.com, Wikipedia), which would also be useful for papers that put to a discussion the degree to which a feature can be obsoleted (e.g. N3353). As an added bonus, defining it highlights existence of a distinction between "obsolete" and "obsolescent", which may not be clear to all readers otherwise.

N3818 Clarify terminology for obsolete features, v2

C23現在はdeprecated属性(→id:yohhoy:20200505)で間接的に定義されているのみ。C23 6.7.13.5/p3より引用。

Semantics
The deprecated attribute can be used to mark names and entities whose use is still allowed, but is discouraged for some reason.174)
脚注174) In particular, deprecated is appropriate for names and entities that are obsolescent, insecure, unsafe, or otherwise unfit for purpose.

C++

C++標準規格ではAnnex Dにて用語 "deprecated" が定義される。C++03/p2より引用。

These are deprecated features, where deprecated is defined as: Normative for the current edition of the Standard, but not guaranteed to be part of the Standard in future revisions.

関連URL

fflush(NULL);

C標準ライブラリ関数fflushにヌルポインタを指定すると、プログラムが現在開いている全てのストリームをフラッシュする。

fflush(NULL);  // OK

C99 7.19.5.2/p1-3より引用(下線部は強調)。

#include <stdio.h>
int fflush(FILE *stream);

2 If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes anyunwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.
3 If stream is a null pointer, the fflush function performs this flushing action on all streams for which the behavior is defined above.

(PDF) C99 Rationale, 7.19.5.2より引用。

The fflush function ensures that output has been forced out of internal I/O buffers for a specified stream. Occasionally, however, it is necessary to ensure that all output is forced out, and the programmer may not conveniently be able to specify all the currently open streams, perhaps because some streams are manipulated within library packages. To provide an implementation-independent method of flushing all output buffers, the Standard specifies that this is the result of calling fflush with a NULL argument.

関連URL

_Exit/_exitはストリームをフラッシュしない

C標準ライブラリ_Exit関数およびPOSIX準拠_exit関数は、プログラムを異常終了させるC標準abort関数と同様に開いているストリーム(FILE型)をフラッシュしない*1。ログファイルや標準出力(stdout)への出力欠落に注意。

一方で、C標準ライブラリexit関数ではストリームフラッシュ動作が保証される。エントリポイントmain関数からのreturnexit関数呼び出しと同義。

C99 5.1.2.2.3, 7.20.4.1/p1-2, 7.20.4.3/p1, p4, 7.20.4.4/p1-2より引用(下線部は強調)。

If the return type of the main function is a type compatible with int, a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument; (snip)

#include <stdlib.h>
void abort(void);

The abort function causes abnormal program termination to occur, unless the signal SIGABRT is being caught and the signal handler does not return. Whether open streams with unwritten buffered data are flushed, open streams are closed, or temporary files are removed is implementation-defined. (snip)

#include <stdlib.h>
void exit(int status);

Next, all open streams with unwritten buffered data are flushed, all open streams are closed, and all files created by the tmpfile function are removed.

#include <stdlib.h>
void _Exit(int status);

The _Exit function causes normal program termination to occur and control to be returned to the host environment. No functions registered by the atexit function or signal handlers registered by the signal function are called. The status returned to the host environment is determined in the same way as for the exit function. Whether open streams with unwritten buffered data are flushed, open streams are closed, or temporary files are removed is implementation-defined.

IEEE Std 1003.1-2024より一部引用(下線部は強調)。この動作仕様はIEEE Std 1003.1-2017で明確化された。

DESCRIPTION
The _Exit() and _exit() functions shall be functionally equivalent.

The _Exit() and _exit() functions shall not call functions registered with atexit() nor at_quick_exit(), nor any registered signal handlers. Open streams shall not be flushed. Whether open streams are closed (without flushing) is implementation-defined. Finally, the calling process shall be terminated with the consequences described below.

CHANGE HISTORY
Issue 7
Austin Group Interpretation 1003.1-2001 #031 is applied, separating these functions from the exit() function.
Austin Group Interpretation 1003.1-2001 #085 is applied, clarifying the text regarding flushing of streams and closing of temporary files.

関連URL

*1:厳密には、C標準ライブラリ仕様では _Exit がストリームをフラッシュするか否かは処理系定義(implementation-defined)とされる。POSIX仕様ではストリームフラッシュ無しと明確に規定する。

bit_castマクロ for C言語

プログラミング言語Cにおいて、ビット表現を維持したまま型変換を安全に行うマクロ。C++標準ライブラリのstd::bit_cast<To>(from)相当。

本記事の内容はStackOverflowで見つけた質問と回答に基づく。

// C99 : 右辺値に未対応
#define bit_cast(T, ...) \
  (*((T*)memcpy(&(T){0}, &(__VA_ARGS__), sizeof(T))))

// C23
#define bit_cast(T, ...) \
  ((union{typeof(T) a; typeof(__VA_ARGS__) b;}) {.b=(__VA_ARGS__)}.a)
// または
#define bit_cast(T, ...) \
  (*(typeof(T)*)memcpy(&(T){0},
    &(typeof(__VA_ARGS__)) {(__VA_ARGS__)}, sizeof(T)))

式static_assert(→id:yohhoy:20250905)を利用して型サイズ検査を組み込んだバージョン:

// C23
#define bit_cast(T, ...) \
  ((union{typeof(T) a; typeof(__VA_ARGS__) b; \
      static_assert(sizeof(T)==sizeof(__VA_ARGS__));}) \
    {.b=(__VA_ARGS__)}.a)

// C11
#define bit_cast(T, ...) \
  ((void)sizeof(struct{int dummy_member; \
     _Static_assert(sizeof(T) == sizeof(__VA_ARGS__), "");}), \
   *((T*)memcpy(&(T){0}, &(__VA_ARGS__), sizeof(T))))
// #include <assert.h>でstatic_assertと記述可能

関連URL




以上の内容はhttps://yohhoy.hatenadiary.jp/より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14