The error against using a class static 'const' field as an array size. The new (arguably) right way to define any class static integral field is here.
Topics
About: C++
The table of contents of this article
- Starting Context
- Target Context
- Main Body
- 1: Meeting the "C2131: expression did not evaluate to a constant" Visual C++ Compile Error
- 2: The Term, "constant", Is Sloppily Used There
- 3: Why the Array Size Is Not Compile-Time Determined
- 4: The New (Arguably) Right Way to Define Any Class Static Integral Field
- 5: But Why Only Integral Fields? A Complaint
Starting Context
- The reader has a basic knowledge on C++.
Target Context
- The reader will know how to solve the "C2131: expression did not evaluate to a constant" Visual C++ compile error and more generally, the new (arguably) right way to define any class static integral field.
Main Body
1: Meeting the "C2131: expression did not evaluate to a constant" Visual C++ Compile Error
Hypothesizer 7
"C2131: expression did not evaluate to a constant"?
Well, I am trying to compile this piece of C++ code with Visual C++.
theBiasPlanet/coreUtilitiesTests/classStaticFieldTest1/TestConstantsGroup.hpp
@C++ Source Code
#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++ Source Code
#include "theBiasPlanet/coreUtilitiesTests/classStaticFieldTest1/TestConstantsGroup.hpp"
namespace theBiasPlanet {
namespace coreUtilitiesTests {
namespace classStaticFieldTest1 {
int const TestConstantsGroup::c_smallBufferSize = 1024;
}
}
}
theBiasPlanet/coreUtilitiesTests/classStaticFieldTest1/Test1Test.hpp
@C++ Source Code
#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++ Source Code
#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"? . . . While the error points to the size specification of the 'l_smallBuffer' array, 'TestConstantsGroup::c_smallBufferSize' is certainly constant, right?
2: The Term, "constant", Is Sloppily Used There
Hypothesizer 7
C++ is notorious for its sloppy terminology. "lvalue", etc., "move semantics", etc., and "static" are some examples.
There, in that error message, "constant" is sloppily used.
That error message seems to mean that the array size is not 'compile-time determined'. Then, please say so.
Note that GCC does not report that error, because GCC does not require any array size to be compile-time determined.
3: Why the Array Size Is Not Compile-Time Determined
Hypothesizer 7
The reason why the array size is not compile-time determined is that any C++ source file is separately compiled.
'Test1Test.cpp' is compiled by itself, without 'StaticVariablesInitializer.cpp' (which determines the class static field value) being refered to. So, the compiler cannot know the value at compile-time.
4: The New (Arguably) Right Way to Define Any Class Static Integral Field
Hypothesizer 7
Then, what am I supposed to do?
The above way to define any class static field is something introduced in an old textbook I have. Rereading the book, in fact, I now have found that the book mentions the problem. The solution the book proposes is to use an 'enum' instead.
Well, I see, but I do not like it very much: it is not along the original purpose of 'enum', I think.
In fact, nowadays (I do not know exactly from when), the class static integral field can be declared and defined like this.
theBiasPlanet/coreUtilitiesTests/classStaticFieldTest1/TestConstantsGroup.hpp
@C++ Source Code
#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++ Source Code
#include "theBiasPlanet/coreUtilitiesTests/classStaticFieldTest1/TestConstantsGroup.hpp"
namespace theBiasPlanet {
namespace coreUtilitiesTests {
namespace classStaticFieldTest1 {
int const TestConstantsGroup::c_smallBufferSize;
}
}
}
Does that solve the problem? Yes: as the value is written in the header file, the array size is determined at the 'Test1Test.cpp' compile-time.
That is better than employing a dirty trick like using 'enum', or using a macro, more dirty.
5: But Why Only Integral Fields? A Complaint
Hypothesizer 7
But that way is allowed for only integral (which means not only 'int' but also 'unsigned int', 'short', 'byte', etc., but not 'double', '::std::string', etc.) fields. Why? . . . I do not see the reason.
I complain because such a restriction causes unreasonable inconsistency in defining class static fields: sometimes, I can set the value in the header file, and at the other times, I have to set the value in the source file.
We should raise complaints on unreasonable specifications.