少し前に、「パラメーター化された」ユーザー定義リテラルについてのアイデアがあり、現在の C++ 標準でこれを行う方法があるかどうか疑問に思っていました。
基本的に、アイデアは、いくつかのパラメーターに従って動作を微調整できるユーザー定義のリテラルを持つことです。簡単な例として、浮動小数点数を整数に変換する「固定小数点」リテラルを選択しました。パラメータは、小数点以下の桁数に関する精度です。
これが実際のアプリケーションでどのように役立つか、または役立つかどうかはわからないため、これは今のところ演習にすぎません。
私の最初のアイデアは次のようなものでした:
namespace fp_impl {
constexpr int floor(long double n) {
return n;
}
constexpr int pow10(int exp) {
return exp == 0 ? 1 : 10 * pow10(exp - 1);
}
template<int i>
constexpr int fixed_point(long double n) {
return floor(n * pow10(i));
}
namespace fp2 {
constexpr int operator"" _fp (long double n) {
return fixed_point<2>(n);
}
}
namespace fp4 {
constexpr int operator"" _fp (long double n) {
return fixed_point<4>(n);
}
}
}
template<int prec> struct fp;
template<> struct fp<2> {
namespace lit = fp2;
};
template<> struct fp<4> {
namespace lit = fp4;
};
int main() {
{
using namespace fp<2>::lit;
std::cout << 5.421_fp << std::endl; // should output 542
}
{
using namespace fp<4>::lit;
std::cout << 5.421_fp << std::endl; // should output 54210
}
}
ただし、名前空間エイリアスはクラス スコープで許可されていないため、コンパイルされません。(また、 のすべてのバージョンを手動で定義する必要があるという問題もありますoperator"" _fp
。) そこで、マクロを使って何かを試すことにしました。
namespace fp {
namespace detail {
constexpr int floor(long double n) {
return n;
}
constexpr int pow10(int exp) {
return exp == 0 ? 1 : 10 * pow10(exp - 1);
}
template<int i>
constexpr int fixed_point(long double n) {
return floor(n * pow10(i));
}
}
}
#define SPEC(i) \
namespace fp { \
namespace precision##i { \
constexpr int operator"" _fp(long double n) { \
return fp::detail::fixed_point<i>(n); \
} \
} \
}
SPEC(2); SPEC(4);
#undef SPEC
#define fp_precision(i) namespace fp::precision##i
int main() {
{
using fp_precision(2);
std::cout << 5.421_fp << std::endl;
}
{
using fp_precision(4);
std::cout << 5.421_fp << std::endl;
}
}
これは機能しますが、使用するSPEC()
すべての精度に対してマクロを使用する必要があります。もちろん、プリプロセッサのトリッキーを使用して、たとえば 0 から 100 までのすべての値に対してこれを行うこともできますが、必要に応じてそれぞれがインスタンス化されるテンプレート ソリューションのようなものがあるのではないかと考えています。テンプレートクラスでフレンド関数として宣言された operator"" を使用するという漠然とした考えがありましたが、それもうまくいかないと思います。
注意として、試してみtemplate<int i> constexpr int operator"" _fp(long double n)
ましたが、これはリテラル演算子の許可された宣言ではないようです。