スポンサーリンク

| キーワード:

C++のconceptについて超初歩的まとめ

(誤解を恐れずに言うなら)conceptはテンプレートで渡す際のclass TのTに条件を付けるための機能。

以下のように、

template<class T>
concept 条件名 = requires(T val){ ... }

という形で定義する。

型Tで与えられた変数valの使い方を定義すると考えると読みやすくなる。

#include <iostream>

// T型の変数valは、print()と++を持たなければならない
template
<class T> concept CallableFunction = requires (T val) { val.print(); // print()関数があることを要求 val.operator++(); // ++演算子があることを要求 };

// CallableFunctionの制約がついている所で使用できるクラス
class MyValidClass {
    int val;
public:
    MyValidClass() {
        val = 5;
    }

    void print() {// print()関数を定義
		std::cout << "val == " << val << std::endl;
	}

    MyValidClass& operator++() {// ++演算子を要求
        ++val;
		return *this;
	}

};

// CallableFunctionの制約がある場合は指定できない。
// operator++() がない。
class MyInvalid {
    int val;
public:
    MyInvalid() {
        val = 5;
    }

    void print() {
        std::cout << "val == " << val << std::endl;
    }
};

// print()関数と++演算子を持つクラスを引数に取る関数
template <CallableFunction Type>
void func(Type val) {
    val.print();
}

int main()
{
    MyValidClass my;

    func(my);
}

式が有効でなければならないという要求を定義

{  } 内に式を書くと、その式を書くことができるような型だけを要求することができる。

#include <iostream>

#include <algorithm>
#include <vector>

template <class T>
concept Sortable = requires (T& val) {

    // { } 内の式が有効であることを要求する書き方ができる。
    // 例えば、以下は T 型の val はソート可能であることを要求する
    {
        std::sort(val.begin(), val.end())
    };

};

// print()関数と++演算子を持つクラスを引数に取る関数
template <Sortable Type>
void func(Type& val) {

    std::sort(val.begin(), val.end());

}

int main()
{
    std::vector<int> my{ 5,3,8 };

    func(my);


    for (auto& i : my) {
        std::cout << i << std::endl;
    }
}

戻り値の要求

{ 式 } で、式が有効であることを要求できるが、式の結果のデータ型を要求するには

{ 式 } -> std::same_as<型>;

とする。

この仕組みを応用すれば、関数の戻り値を要求できる。

#include <iostream>

#include <algorithm>
#include <vector>

template <class T>
concept Sizable = requires (T & val) {

    {
        val.size() // size()関数を持つ

    }->std::same_as<size_t>; // size()関数の戻り値はsize_t型
    // std::same_asはconcept。式の戻り値の型を指定する。
};

class MyArray {
    std::vector<int>vec;   
public: 
    void push_back(int i) { vec.push_back(i); }
    int size() { return vec.size(); }
};

// この関数は、戻り値がsize_t型のsize()関数を持つ型しか受け付けない
template <Sizable Type>
void func(Type& val) {

    std::cout<<val.size()<<std::endl;

}

int main()
{
    std::vector<int> my;
    // MyArray my;

    my.push_back(3);
    my.push_back(1);
    my.push_back(8);

    func(my);

}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: