yohhoyの日記

技術的メモをしていきたい日記

"Dreams come" == true

プログラミング言語PHPにおける奇妙な型変換 "Type Juggling"・第2弾。真偽値との比較にも要注意。

<?php
var_dump("Dreams come" == true);
// bool(true)

var_dump("Dreams come" === true);
// bool(false)
?>

Type Juggling規則により「片方がbool型の場合は両辺をbool型として比較評価」する。

関連URL

演算子オーバーロード for 日付リテラル

C++20標準ヘッダ <chrono> カレンダー(Calendar)ライブラリが提供する、日付リテラル表記用の/演算子オーバーロード一覧。

ノート:年月日順で日付リテラルを述する場合、少なくとも年(year)フィールドは常に型を明示した方がトラブルリスク*1が小さい。/演算子は左結合となることをお忘れなく。

#include <chrono>
using namespace std::chrono;

// 2022-06-13
auto date1 = 2022y/6/13;    // OK: year_month_day{year{2022}, month{6}, day{13}}
auto date2 = 2022/June/13;  // NG: ill-formed
auto date3 = 2022/6/13d;    // NG: month_day{month{337}, day{13}}
auto date4 = 2022/6/13;     // NG: int{25}

auto date2m = 2022/(June/13);  // OK: 意図通りに解釈されはするものの
auto date2d = 2022/(6/13d);    // OK: これらの難解表記は避けるべき…

年月日指定:*2

左辺 右辺 結果 表記
year month year_month 年/月 *
year int year_month 年/月 *
month day month_day 月/日 *
month int month_day 月/日 *
int day month_day 月/日 *
day month month_day 日/月
day int month_day 日/月
year_month day year_month_day 年+月/日 *
year_month int year_month_day 年+月/日 *
year month_day year_month_day 年/月+日 *
int month_day year_month_day 年/月+日 *
month_day year year_month_day 月+日/年
month_day int year_month_day 月+日/年

最終日指定:*3

左辺 右辺 結果 表記
month last_spec month_day_last 月/最終日 *
int last_spec month_day_last 月/最終日 *
last_spec month month_day_last 最終日/月
last_spec int month_day_last 最終日/月
year month_day_last year_month_day_last 年/月+最終日 *
int month_day_last year_month_day_last 年/月+最終日 *
month_day_last year year_month_day_last 月+最終日/年
month_day_last int year_month_day_last 月+最終日/年

第n曜日指定:

左辺 右辺 結果 表記
month weekday_indexed month_weekday 月/第n曜日 *
int weekday_indexed month_weekday 月/第n曜日 *
weekday_indexed month month_weekday 第n曜日/月
weekday_indexed int month_weekday 第n曜日/月
year_month weekday_indexed year_month_weekday 年+月/第n曜日 *
year month_weekday year_month_weekday 年/月+第n曜日 *
int month_weekday year_month_weekday 年/月+第n曜日 *
month_weekday year year_month_weekday 月+第n曜日/年
month_weekday int year_month_weekday 月+第n曜日/年

最終曜日指定:*4

左辺 右辺 結果 表記
month weekday_last month_weekday_last 月/最終曜日 *
int weekday_last month_weekday_last 月/最終曜日 *
weekday_last month month_weekday_last 最終曜日/月
weekday_last int month_weekday_last 最終曜日/月
year_month weekday_last year_month_weekday_last 年+月/最終曜日 *
year month_weekday_last year_month_weekday_last 年/月+最終曜日 *
int month_weekday_last year_month_weekday_last 年/月+最終曜日 *
month_weekday_last year year_month_weekday_last 月+最終曜日/年
month_weekday_last int year_month_weekday_last 月+最終曜日/年

関連URL

*1:date3 は std::chrome::month クラスの未規定(unspecified)仕様により、大半のC++処理系で month_day{month{81}, day{13}} として保持される可能性が高い。(C++20 27.8.4.1/p1, 27.8.4.2/p1)

*2:ISO 8601準拠の記述順(年-月-日)のみをサポートするならば、表中 * 印オーバーロードのみで十分だったはず。

*3:ある月の最終日表現には std::chrono::last 定数を用いる。

*4:ある月の最終曜日を std::chrono::weekday_last 型 = std::chrono::weekday 型 + std::chrono::last 定数で表現する。

*5:C++20のベースとなったCalendarライブラリに関するCppCon 2015プレゼンテーション

{void,value,both}-compatibleラムダ式

プログラミング言語Javaにおけるラムダ式は、その本体部に応じてvoid-compatible/value-compatible/その両方に区分される。

void-compatibleラムダ式Runnableなどの戻り値を持たない(void)関数型インタフェース(functional interface)へ、value-compatibleラムダ式IntSupplierなどの戻り値をもつ関数型インタフェースへと代入できる。

import java.util.function.IntSupplier;

// void-compatible
Runnable    r1 = () -> { };  // OK
IntSupplier s1 = () -> { };  // NG

// value-compatible
Runnable    r2 = () -> { return 42; };  // NG
IntSupplier s2 = () -> { return 42; };  // OK

// void-compatible かつ value-compatible
Runnable    r3 = () -> { throw new NullPointerException(); };  // OK
IntSupplier s3 = () -> { throw new NullPointerException(); };  // OK
final boolean TRUE = true;
Runnable    r4 = () -> { while (TRUE); };  // OK
IntSupplier s4 = () -> { while (TRUE); };  // OK

Java Language Specification, Java SE 8 Editionより一部引用。

The rules in this section define two technical terms:

  • whether a statement is reachable
  • whether a statement can complete normally

(snip)

The rules are as follows:

  • (snip)
  • A while statement can complete normally iff at least one of the following is true:
    • The while statement is reachable and the condition expression is not a constant expression (§15.28) with value true.
    • There is a reachable break statement that exits the while statement.
  • (snip)
  • A break, continue, return, or throw statement cannot complete normally.
  • (snip)
Chapter 14. Blocks and Statements, 14.21. Unreachable Statements

A block lambda body is void-compatible if every return statement in the block has the form return;.

A block lambda body is value-compatible if it cannot complete normally (§14.21) and every return statement in the block has the form return Expression;.

(snip)

Note that the void/value-compatible definition is not a strictly structural property: "can complete normally" depends on the values of constant expressions, and these may include names that reference constant variables.

Chapter 15. Expressions, 15.27.2. Lambda Body

関連URL

returns_twice属性

GCCとClangの独自拡張 returns_twice 属性についてメモ。

対象関数から「2回以上制御が戻ってくる可能性」*1コンパイラに伝える属性。コンパイラによる一部の最適化処理を抑止する。

The returns_twice attribute tells the compiler that a function may return more than one time. The compiler ensures that all registers are dead before calling such a function and emits a warning about the variables that may be clobbered after the second return from the function. Examples of such functions are setjmp and vfork. The longjmp-like counterpart of such function, if any, might need to be marked with the noreturn attribute.

https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html

returns_twice
This attribute indicates that this function can return twice. The C setjmp is an example of such a function. The compiler disables some optimizations (like tail calls) in the caller of these functions.

https://llvm.org/docs/LangRef.html

関連URL

*1:関数から制御が戻ってこないことを表明するnoreturn属性と対をなす。

-fimplicit-constexprオプション

gcc(g++) 12.1にて、inline関数に対して暗黙に constexpr 指定を行うコンパイルオプション -fimplicit-constexpr が導入された。同オプションはC++14/17/20言語仕様に対する独自拡張として機能する。

With each successive C++ standard the restrictions on the use of the constexpr keyword for functions get weaker and weaker; it recently occurred to me that it is heading toward the same fate as the C register keyword, which was once useful for optimization but became obsolete. Similarly, it seems to me that we should be able to just treat inlines as constexpr functions and not make people add the extra keyword everywhere.

https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=87c2080b

関連URL

連番配列を生成

JavaScript(ECMAScript)で連番配列を生成するコード片。いわゆる range 関数に相当。

// NG: [undefined, undefined, undefined, undefined, undefined]
// { length: 5 } のみ設定されたArrayオブジェクトが生成される
// 各要素は未設定(undefinedとも異なる状態)となっている
Array(5).map((val, idx) => idx);
[,,,,,].map((val, idx) => idx);

// OK: [0, 1, 2, 3, 4]
Array(5).fill(undefined).map((val, idx) => idx);
Array(5).fill(0).map((val, idx) => idx);
Array.from(Array(5), (val, idx) => idx);
Array.from({length: 5}, (val, idx) => idx);
[...Array(5)].map((val, idx) => idx);
[...Array(5).keys()];

関連URL

std::expected<T, E>

次期C++2b(C++23)標準ライブラリに追加されるstd::expected<T, E>クラステンプレートについてメモ。

  • 従来C++例外機構(throw文+try/catch構文)に代わり、関数の演算結果(T型)またはエラー情報(E型)を “値” として返す(return)ための部品。
  • C++17 std::optional<T>型の無効値(std::nullopt)表現に代わり、具体的なエラー情報(E型)を保持可能に拡張された型。*1
  • 新しい標準ヘッダ<expected>
    • クラステンプレートexpected<T, E>、補助型unexpected<E>*2、タグunexpect、例外型bad_expected_access<E>
  • expected<T, E> == 結果Tとエラーunexpected<E>の直和型*3
    • constexpr文脈でも利用可能
    • expected<void, E>特殊化 == エラーのみを保持する
    • std::optional同様に参照型は未サポート
  • expected<T, E>型への代入:
    • 結果/Tへ変換可能な型:r = t;またはr = {std::in_place, t};*4
    • エラー/Eへ変換可能な型:r = std::unexpected(e);またはr = {std::unexpect, e};
  • 保持値アクセス:
    • 結果/エラー保持判定:has_value, explicit operator bool*5
    • 結果(T型):value, value_or, operator->, operator*
    • エラー(E型):error
    • 結果未保持でのvalueメンバ関数呼び出しはstd::bad_expected_access<E>{error()}例外送出
    • 結果未保持での間接参照(->, *)アクセスは未定義動作(undefined behavior)*6
    • エラー未保持でのerrorメンバ関数呼び出しは未定義動作
  • expectedモナディック(monadic)操作はC++2bには間に合わず*7C++2c(C++26)向け提案文書 P2505 にて継続検討中。
    • C++2b標準ライブラリoptionalモナディック操作(and_then, or_elseなど)は P0789R8 が採択済み。
    • 2022-11-29追記:2022年11月会合で提案文書P2505R5が採択され、C++2b標準ライブラリにexpectedモナディック操作群が追加される。

Boost.Outcomeライブラリとの比較:

関連URL

*1:std::optional<T> ≒ std::expected<T, std::nullopt_t>

*2:C++20現在、識別子 unexpected はZombie nameとして予約されおり、expected<T, E> 導入に伴ってC++2bで蘇生(?)された初のケース。C++的ゾンビのお名前 参照。

*3:無効値 nullopt でデフォルト構築される std::optional<T> とは異なり、エラー情報を明示的に保持する std::expected<T, E> ではデフォルト構築後は結果値 T{} を保持している。

*4:https://cpprefjp.github.io/reference/utility/in_place_t.html

*5:if文の条件式などに expected<T, E> 型の値を記述することで、結果を保持しているか否かを判定可能(→id:yohhoy:20121110

*6:提案文書P0323R12 §3.14: "Using the indirection operator for an object that does not contain a value is undefined behavior. This behavior offers maximum runtime performance."

*7:https://github.com/cplusplus/papers/issues/1161#issuecomment-1027125553