yohhoyの日記

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

可変引数リストと非PODクラス型の関係・改

gcc(g++)5以降では、C言語スタイルの可変引数リスト(...)に非PODクラス型(≒普通のC++クラス型)を渡すことができる。

注意:この振る舞いはgcc 5以降という特定の処理系でのみ合法であり*1、またC++の型システムを無視するため、強い理由がない限りは利用しないこと。

#include <cstdio>
#include <cstdarg>

// 非POD型
struct X {
  X() { std::puts("ctor"); }
  ~X() { std::puts("dtor"); }
  X(const X&) { std::puts("copy"); }
  X& operator=(const X&) { std::puts("copy"); return *this; }
};

void f(int n, ...)
{
  va_list ap;
  va_start(ap, n);
  X x = va_arg(ap, X);  // OK(conditionally-supported)
  va_end(ap);
}

int main()
{
  X x;
  f(0, x);  // OK(conditionally-supported)
}

-Wconditionally-supportedオプションを指定しない限り、上記コードは警告なしに正常にコンパイルされる*2。関数実装でva_listを介して実引数にアクセスする際は、va_argマクロに型名(上記コードではX)を指定する。

C++11
可変引数リストに非自明なコピー/ムーブコンストラクタまたは非自明なデストラクタをもつクラス型を渡した場合、処理系によってはサポートされ(conditionally-supported)、そのセマンティクスは処理系定義(implementation-defined)となる。N3337 1.3.5, 5.2.2/7より一部引用。
(省略)

可変引数リストと非PODクラス型の関係

gcc 5.4ドキュメントより該当箇所を引用。

Whether an argument of class type with a non-trivial copy constructor or destructor can be passed to ... (C++0x 5.2.2).
 Such argument passing is supported, using the same pass-by-invisible-reference approach used for normal function arguments of such types.

5.1 Conditionally-Supported Behavior

関連URL

*1:Clang 3.8ではコンパイルエラー

*2:-Wconditionally-supported オプション指定時の警告メッセージ:passing objects of non-trivially-copyable type 'struct X' through '...' is conditionally supported [-Wconditionally-supported]