yohhoyの日記

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

プライマリ変数テンプレート無効化の実装例

C++2a(C++20)標準ライブラリ<numbers>では、変数テンプレート(variable template)*1により浮動小数点型(float, double, long double)にあわせた数学定数を提供する。一方、浮動小数点型以外によるプライマリテンプレート利用はill-formedとなることが要請されている。

#include <numbers>

// float型精度の円周率π
float pi_f = std::numbers::pi_v<float>;  // OK
// int型の円周率π?
int pi_i = std::numbers::pi_v<int>;  // NG: ill-formed

N4861 (C++2a DIS) 26.9.2/p3より引用。

A program that instantiates a primary template of a mathematical constant variable template is ill-formed.

GCC/libstdc++

https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/numbers

template<typename _Tp>
  using _Enable_if_floating = enable_if_t<is_floating_point_v<_Tp>, _Tp>;

template<typename _Tp>
  inline constexpr _Tp pi_v
    = _Enable_if_floating<_Tp>(3.14159...);

Clang/libcxx

https://github.com/llvm/llvm-project/blob/master/libcxx/include/numbers

template <class T>
inline constexpr bool __false = false;

template <class T>
struct __illformed
{
  static_assert(__false<T>, "...");
};

template <class T> inline constexpr T pi_v =  __illformed<T>{};

template <class T>
concept __floating_point = std::is_floating_point_v<T>;

template <__floating_point T> inline constexpr T pi_v<T> = 3.14159...;

MSVC

https://github.com/microsoft/STL/blob/master/stl/inc/numbers

// stl/inc/xstddef
template <class>
inline constexpr bool _Always_false = false;

template <class _Ty>
struct _Invalid {
  static_assert(_Always_false<_Ty>, "...");
};

template <class _Ty>
inline constexpr _Ty pi_v = _Invalid<_Ty>{};

template <floating_point _Floating>
inline constexpr _Floating pi_v<_Floating> = static_cast<_Floating>(3.14159...);

関連URL

*1:変数テンプレートは C++14 で追加された機能。