2021年1月3日日曜日

14: 「C2131: expression did not evaluate to a constant」Visual C++コンパイルエラー?

<このシリーズの前の記事 | このシリーズの目次 | このシリーズの次の記事>

クラススタティックコンスタントフィールドを配列サイズとして使うことに対するエラー。任意のクラススタティック整数フィールドを定義するための新たな正しい(異論はあるかもしれないが)方法がここにあります。

話題


About: C++

この記事の目次


開始コンテキスト


  • The reader has a basic knowledge on C++. 読者は、C++の基本的知識を持っている。

ターゲットコンテキスト



  • 読者は、「C2131: expression did not evaluate to a constant」Visual C++コンパイルエラーを解決する方法、およびもっと一般的に、任意のクラススタティック整数フィールドを定義するための新たな正しい(異論はあるかもしれないが)方法を知る。

本体


1: 「C2131: expression did not evaluate to a constant」Visual C++コンパイルエラーに遭遇する


Hypothesizer 7
「C2131: expression did not evaluate to a constant」?

えーと、私は以下のC++コードをVisual C++でコンパイルしようとしている。

theBiasPlanet/coreUtilitiesTests/classStaticFieldTest1/TestConstantsGroup.hpp

@C++ ソースコード
#ifndef __theBiasPlanet_coreUtilitiesTests_classStaticFieldTest1_TestConstantsGroup_hpp__
	#define __theBiasPlanet_coreUtilitiesTests_classStaticFieldTest1_TestConstantsGroup_hpp__
	
	namespace theBiasPlanet {
		namespace coreUtilitiesTests {
			namespace classStaticFieldTest1 {
				class TestConstantsGroup {
					public:
						static int const c_smallBufferSize;
				};
			}
		}
	}
#endif

theBiasPlanet/coreUtilitiesTests/staticVariablesInitializer/StaticVariablesInitializer.cpp

@C++ ソースコード
#include "theBiasPlanet/coreUtilitiesTests/classStaticFieldTest1/TestConstantsGroup.hpp"

namespace theBiasPlanet {
	namespace coreUtilitiesTests {
		namespace classStaticFieldTest1 {
			int const TestConstantsGroup::c_smallBufferSize = 1024;
		}
	}
}

theBiasPlanet/coreUtilitiesTests/classStaticFieldTest1/Test1Test.hpp

@C++ ソースコード
#ifndef __theBiasPlanet_coreUtilitiesTests_classStaticFieldTest1_Test1Test_hpp__
	#define __theBiasPlanet_coreUtilitiesTests_classStaticFieldTest1_Test1Test_hpp__
	
	namespace theBiasPlanet {
		namespace coreUtilitiesTests {
			namespace classStaticFieldTest1 {
				class Test1Test {
					public:
						static int main (int const & a_argumentsNumber, char const * const a_arguments []);
						static void test ();
				};
			}
		}
	}
#endif

theBiasPlanet/coreUtilitiesTests/classStaticFieldTest1/Test1Test.cpp

@C++ ソースコード
#include "theBiasPlanet/coreUtilitiesTests/classStaticFieldTest1/Test1Test.hpp"
#include "theBiasPlanet/coreUtilitiesTests/classStaticFieldTest1/TestConstantsGroup.hpp"

namespace theBiasPlanet {
	namespace coreUtilitiesTests {
		namespace classStaticFieldTest1 {
			int Test1Test::main (int const & a_argumentsNumber, char const * const a_arguments []) {
				return 0;
			}
			
			void Test1Test::test () {
				char l_smallBuffer [TestConstantsGroup::c_smallBufferSize];
			}
		}
	}
}

「did not evaluate to a constant」?. . .そのエラーは'l_smallBuffer'配列のサイズ指定を指しているが、'TestConstantsGroup::c_smallBufferSize'は、間違いなくコンスタントでしょう?


2: The Term, "constant", Is Sloppily Used There 「constant」という用語は、そこでずさんに使われている


Hypothesizer 7
C++は、そのずさんな用語体系で悪名高い。「lvalue」、等「ムーブセマンティクス」、等、「static」は、その例だ。

そのエラーメッセージ中のそこで、「constant」は、ずさんに使われている。

そのエラーメッセージは、配列サイズが'コンパイル時決定'されていないということをいいたいように思われる。それなら、そう言ってください。

注意すべきだが、GCCはそのエラーを報告しない、なぜなら、GCCは、配列サイズがコンパイル時決定されていることを要求しないから。


3: なぜ、その配列サイズはコンパイル時決定されないのか


Hypothesizer 7
その配列サイズがコンパイル時決定されない理由は、C++ソースファイルはどれも個別にコンパイルされるから。

'Test1Test.cpp'は、それだけでコンパイルされる、'StaticVariablesInitializer.cpp'(それが、クラススタティックフィールド値を決定する)は参照されずに。したがって、コンパイラーは、その値をコンパイル時に知ることができない。


4: 任意のクラススタティック整数フィールドを定義するための新たな正しい(異論はあるかもしれないが)方法


Hypothesizer 7
それでは、私はどうするよう想定されているのか?

任意のクラススタティックフィールドを定義するための上記の方法は、私が持っているある古いテキストブック中で紹介されているものだ。その本を読み直したところ、実のところ、その本がその問題に言及していることを今、発見した。その本が提案する解決策は、代わりに、'enum'を使うことだ。

えーと、分かります、しかし、私はそれがあまり好きではない: それは、'enum'の元来の目的に沿うものではない、と私は思う。

実は、最近は(厳密にいつからなのか私は知らない)、クラススタティック整数フィールドは、以下のようにk、宣言および定義できる。

theBiasPlanet/coreUtilitiesTests/classStaticFieldTest1/TestConstantsGroup.hpp

@C++ ソースコード
#ifndef __theBiasPlanet_coreUtilitiesTests_classStaticFieldTest1_TestConstantsGroup_hpp__
	#define __theBiasPlanet_coreUtilitiesTests_classStaticFieldTest1_TestConstantsGroup_hpp__
	
	namespace theBiasPlanet {
		namespace coreUtilitiesTests {
			namespace classStaticFieldTest1 {
				class TestConstantsGroup {
					public:
						static int const c_smallBufferSize = 1024;
				};
			}
		}
	}
#endif

theBiasPlanet/coreUtilitiesTests/staticVariablesInitializer/StaticVariablesInitializer.cpp

@C++ ソースコード
#include "theBiasPlanet/coreUtilitiesTests/classStaticFieldTest1/TestConstantsGroup.hpp"

namespace theBiasPlanet {
	namespace coreUtilitiesTests {
		namespace classStaticFieldTest1 {
			int const TestConstantsGroup::c_smallBufferSize;
		}
	}
}

それは問題を解決するのか?イエス: 値がヘッダーファイルに書かれているので、その配列サイズは、'Test1Test.cpp'コンパイル時に決定される。

その方法が、'enum'を使うようなダーティな(あるいは、もっとダーティに、マクロを使う)トリックを用いるするよりも良い。


5: しかし、なぜ、整数フィールドだけなのか?ある不平


Hypothesizer 7
しかし、その方法は、整数(それは、'int'だけでなく、'unsigned int'、'short'、'byte'、等も意味するが、'double'、'::std::string'、等は意味しない)フィールドにのみ許されている。なぜなのか?. . .私は理由を見いださない。

私が不平を言う理由は、そのような制約は、クラススタティックフィールド群の定義にアンリーズナブルな不一貫性を引き起こすことだ: ある時は、値をヘッダーファイルにセットでき、その他の時は、値をソースファイルにセットしなければならない。

アンリーズナブルな仕様には、私たちは、不平の声を上げるべきだ。


参考資料


<このシリーズの前の記事 | このシリーズの目次 | このシリーズの次の記事>