C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++17の新機能まとめ|押さえておきたい6つの主要機能を解説

C++の標準化委員会は、3年ごとに新しい機能を取り入れた標準規格の策定を続けています。仕様は大きく分けて、プログラミング言語のコア機能と標準テンプレートライブラリ(STL)の2つで構成されており、C++17ではコードをよりクリーンで簡潔、かつ書きやすくするための数々の新機能が導入されました。

この記事では、C++17で追加された主要な新機能を6つに分けて、構文やサンプルコードとともにわかりやすく解説します。

1. 畳み込み式(Fold Expressions)

畳み込み式は、可変個の引数を関数に渡したり関数から返したりする際に、より短いコードを書くための機能です。任意の個数の変数を引数として扱えるだけでなく、return文でも活用できます。

構文

  • 単項右畳み込み:( pack op1 ... )
  • 単項左畳み込み:( ... op1 pack )
  • 二項左畳み込み:( init op1 ... op1 pack )
  • 二項右畳み込み:( pack op1 ... op1 init )

packはパラメーターパックで、任意の個数の変数に展開できます。op1には演算子(-、+、<=、>=、<、>、==、*、/など)を指定します。二項畳み込みの場合、両方のop1は同じ演算子である必要があります。またinitは、展開できない式(初期値)を表します。

使用例

#include <iostream>
#include <string>
using namespace std;
template<typename ...Args> auto addition(Args ...args){
    return (args + ... + 0);
}
template<typename ...Args> auto sum2(Args ...args){
    return (args + ...);
}
int main(){
   cout << "Sum is : " << addition(1,1,1,1,1) << endl;
   cout << "Sum 2 is : " << sum2(1,2,3);
}

実行結果

Sum is : 5
Sum 2 is : 6

2. 構造化束縛(Structured Bindings)

構造化束縛は、pairやtupleなどに格納された複数の値を使って、複数の変数を同時に宣言・初期化できる機能です。すべての変数へのバインドを、たった1つのステートメントで完結できます。

  • ケース1:配列のバインド

    識別子リスト内の各識別子は、配列の各要素に対するlvalueの名前になります。要素数と識別子の数は一致していなければなりません。

    int arry[3] = { 3, 4, 5 };
    auto [a, b, c] = arry;
    // a は 3、b は 4、c は 5 を参照します
  • ケース2:tuple風の型へのバインド

    float fnum{};
    char ch1{};
    int number{};
    std::tuple < float&, char&&, int > tplex( fnum, std::move(ch1), number);
    const auto& [ p, q, r ] = tplex;
    // p は fnum を参照する構造化束縛の名前
    // q は ch1 を参照する構造化束縛の名前
    // r は number を参照する構造化束縛の名前
  • ケース3:データメンバーへのバインド

    struct structVar {
        mutable int num1 : 2;
        volatile double num2;
    };
    structVar func();
    const auto [ a, b ] = func();
    // a は2ビットのビットフィールドに対する int 型の lvalue
    // b は const volatile double 型の lvalue

3. enum型の波括弧による直接リスト初期化

C++17からは、enum型を波括弧({})を使って初期化できるようになりました。

構文

enum byte : unsigned char {};
byte b0 {0};           // OK
byte b1 = byte{1};     // OK
byte b2 = byte{256};   // エラー - 指定できるのは0〜255まで

4. if文・switch文内での変数宣言

C++17では、if文やswitch文の条件部分の中で変数を宣言できるようになりました。これにより、異なるスコープを持つ同じ名前の変数を扱いやすくなり、変数の有効範囲を最小限に抑えた安全なコードが書けます。

構文

if (データ型 変数 = 初期値; 条件)
{
   // ステートメント
}
switch (初期化; 条件)
{
   // ステートメント
}

5. if constexpr文

if constexprは、テンプレートコードで特に有用な機能です。この文はコンパイル時に評価されるため、実行時のオーバーヘッドなしに条件分岐を実現できます。

従来のif-else文

int var = 10;
if (var >= 10) {
   var = var + 10;
} else {
   var = var - 10;
}

constexpr if-else文

template <typename T>
auto length( T const& value ) {
   // T が整数型かどうかを判定
   if constexpr (is_integral<T>::value) {
       return value;
   } else {
       return value.length();
   }
}

6. ネストされた名前空間(Nested Namespaces)

名前空間は、関連性のあるクラスや関数などのコードをグループ化するために使われます。C++17では、ネストされた名前空間をより簡潔な構文で記述できるようになりました。以前はネストの階層が深くなるほど構文が煩雑になり、閉じ括弧の管理も大変でしたが、新しいスコープ解決演算子(::)を使った記法なら、その必要はありません。

C++17以前の書き方

namespace Earth {
   namespace Continent {
      namespace Country {
         class City {
         // ..........
}; } } }

新しい構文(C++17)

namespace Earth :: Continent :: Country {
   class City {
      // ..........
}; }

まとめ

C++17では、畳み込み式や構造化束縛、if constexpr、ネストされた名前空間など、テンプレートプログラミングや日常的なコーディングの生産性を高める機能が多数追加されました。これらの機能を活用することで、より読みやすく保守しやすいモダンなC++コードを書けるようになります。ぜひ実際のプロジェクトでも試してみてください。

  1. Twitter、新タイムライン機能「最高のツイートを先頭に表示」を発表―設定方法を徹底解説

    競争の激しいSNS業界で存在感を保つため、Twitterは絶えず新機能を追加しています。今回発表されたのは、新しいタイムライン機能です。この機能により、ひとつの話題に関するツイートがまとめて表示され、ユーザーはさまざまな視点からの情報を簡単に確認できるようになります。 Twitterはインターフェースがやや複雑で、一般ユーザーにとって使いにくいという声がありました。こうした課題を解消するべく、Twitterはすべてのユーザーの利便性向上につながる新機能を公開したのです。 以前からある「不在時のまとめ(While you were away)」機能は、離れている間に投稿されたツイートのおさらいを

  2. Facebookが大転換!F8カンファレンスで発表された新機能を徹底解説

    ここ数ヶ月、Facebookは大型スキャンダルが相次ぎ、アカウントを削除するユーザーも続出するなど、非常に厳しい時期を過ごしてきました。Cambridge Analytica問題への批判の矢面に立ちながらも、CEOであるマーク・ザッカーバーグは、同社ソーシャルメディアプラットフォームの未来に対して楽観的な姿勢を崩していません。カリフォルニア州サンノゼで開催された開発者向けイベント「F8カンファレンス」のステージで、Facebookおよびその傘下サービスに搭載される数々の新機能を発表しました。 ザッカーバーグはこう語ります。「私たちには解決すべき現実的な課題がありますが、楽観的な姿勢も持ち続けな