constexprラムダ式で包んだconstexpr変数をconstexprではない関数に渡すお話

g++7.2.0とclang5.0.0で確認してたはず。

方法

constexprではない通常の関数にconstexpr変数を渡すことはできません。

// これはもちろんコンパイルエラー

void func(char const* x)
{
    constexpr auto y = x;
}

int main()
{
    constexpr auto x = "abc";
    func( x );
}

そこで、C++17で追加されたconstexprラムダ式を使います。constexprラムダ式でconstexpr変数を包むことで、通常の関数でもconstexpr変数を渡すことができるようになります。

// これは通る

template <typename F>
void func(F f)
{
    constexpr auto y = f();
}

int main()
{
    // 明示的にconstexprラムダ式を書いた場合
    func( []() constexpr { return "abc"; } );

    // constexprラムダ式でもキャプチャできるので
    constexpr auto x = "abc";
    func( [&]{ return x; } );
}

条件を満たせばラムダ式のconstexprを暗黙にすることができる(N4659 [expr.prim.lambda.closure]/p4)ので、引数がない場合に()を省略できることを合わせて、以下のように簡単にすることができます。

int main()
{
    func( []{ return "abc"; } );
}

最後に

これを応用することで、printfのフォーマットのコンパイル時チェック等ができたりします。
 
 

・・・やっぱり本当にいいの、これ?

参考

ラムダ式を使って関数の引数からconstexpr変数を定義できたことに関する質問 - スタック・オーバーフロー
https://ja.stackoverflow.com/questions/38123/

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.