yohhoyの日記

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

declcall演算子

プログラミング言語C++の次期標準C++2c(C++26)に導入されるdeclcall演算子についてメモ。

declcall演算子は関数呼び出しを含む式をオペランドにとり、オーバーロード解決後の関数ポインタ/メンバ関数ポインタを返す定数式(constant expression)となる。このときdeclcall演算子オペランドは評価されない(unevaluated)。

// C++2c
#include <functional>

void f(int);    // #1
void f(float);  // #2

auto pf1 = declcall(f(0)  ); // #1のアドレス
auto pf2 = declcall(f(.0f)); // #2のアドレス

std::function<void(int)> fn0{f};  // NG: ill-formed
std::function<void(int)> fn1{declcall(f(0))};  // OK: #1

declcall演算子の固有機能として、仮想メンバ関数呼び出し式に適用すると脱仮想化ポインタ(devirtualized pointer)を生成する。下記例示においてpmf2は基底クラスのメンバ関数B::mfに固定された脱仮想化ポインタとなる。

// C++2c
#include <cassert>
#include <concepts>

struct B {
  virtual int mf() { return 1; }
};
struct D : B {
  virtual int mf() override { return 2; }
};

D obj;
assert(obj.mf() == 2);     // D::mf
assert(obj.B::mf() == 1);  // B::mf

auto pmf1 = &B::mf;  // int(B::*)()
assert((obj.*pmf1)() == 2);  // D::mf

auto pmf2 = declcall(obj.B::mf());  // int(B::*)()
assert((obj.*pmf2)() == 1);  // B::mf (devirtualized)

ノート:演算子declcallは、評価されないコンテキストにおいて指定型の値を生成するヘルパ関数std::declvalからの連想と考えられる。

関連URL