読者です 読者をやめる 読者になる 読者になる

ゲーム作りは楽しい

なんか書く

constexprでテンプレートメソッドパターンやろうとしたら、よくわからんくなった話

C++

そもそもテンプレートメソッドパターンとは、以下のようにアクセスするpublicのメンバ関数内で、(純粋)仮想関数などを使用し、決められた型にはまった動作を行うようにするデザインパターンです。

class Original
{
protected:
	int m_num;

	virtual int cal()const=0;

public:
	Original(const int num):
		m_num(num)
	{}

	void value()const
	{
		cout << "値は:"<< this->cal()<<endl;
		
	}
};

class Square : public  Original
{
private:
	int cal() const override
	{
		return m_num*m_num;
	}

public:

	Square(const int num):
		Original(num)
	{}

};

//後で比較するためにあえてここに作る
const Square num(2);

void main()
{
	num.value();
}

これの場合は

  1. 「値は」と出力
  2. 何かわからんがcal関数で計算された値が出力

というだけの枠組みに決まったvalue()関数である。


ですがconstexprを学びだした僕はこう思ったわけです
ん?おいまてよ、これくらいならconstexprにしたいぞと、

ってことでconstexprにしてみる

class Original
{
protected:
	int m_num;

	virtual int hoge()const=0;

public:
	constexpr Original(const int num):
		m_num(num)
	{}

	void value()const
	{
		cout << "値は:"<< this->hoge()<<endl;
		
	}
};

class Square : public  Original
{
private:
	int hoge() const override
	{
		return m_num*m_num;
	}

public:

	constexpr Square(const int num):
		Original(num)
	{}

};

constexpr Square num(2);

void main()
{

	num.value();
}

やってやったぞ!優勝!!!と思ったあなたは大間違い

これを実行すると…動作が停止します。

thisがねえって怒られます。
constexprはvirtualメソッドがNGって聞きます。つまりはダメ

ちなみに下みたいにしたら問題なく動いたのですが、その理由がわからない(T T)

void main()
{
	constexpr Square num(2);

	num.value();
}


h内に書いたりした場合ももちろん動作は停止。

では、どうやって解決するかですが

templateを使って静的ポリモーフィズムのようにします

template<class _T>
class Original
{
protected:
	int m_num;

public:
	constexpr Original(const int num):
		m_num(num)
	{}

	void value()const
	{
		cout << "値は:"<< static_cast<const _T&>(*this).cal()<<endl;
		
	}
};

class Square : public  Original<Square>
{
	friend class Original<Square>;
private:
	int cal() const
	{
		return m_num*m_num;
	}

public:

	constexpr Square(const int num):
		Original(num)
	{}

};

おいおいfriendがでてきたぞと、
friendとはそのclassに自身のprivateやprotectedのメンバへのアクセスを許可するものです。
hogeをpublicにすればいいのですが、それではテンプレートメソッドを使ってるメリットがなくなってしまいます。

これでOKですが…

Originalにhogeさえ持ってればどんなclassでも_Tに渡せる状態なのでわりと危険かな
(static_castしてるのでそこでエラーは、はいてくれるが)


templateを使うたびにやばいこと(危険なこと)してる気がしてます。