Expected constant expression

Hi there,

const-correctness and static member variables are domains of the language I haven't entirely grasped. I'm working on a larger project, but the following is a snippet of a dummy project which reproduces the same error:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
namespace Test {

	const __int64 num_channels = 2;
	const __int64 samplerate = 44100;
	const __int64 tempo = 120;
	const __int64 num_seconds_in_minute = 60;
	const __int64 num_beats_per_bar = 4;
	const __int64 num_seconds_in_buffer = ((double)num_beats_per_bar / ((double)tempo / (double)num_seconds_in_minute));

	typedef __int16 BitDepth;

	class Buffer {
	public :
		Buffer() {}

		const static __int64 num_samples = num_seconds_in_buffer * samplerate * num_channels;
		BitDepth samples[num_samples];
	};
}

int main() {

	Test::Buffer buffer;

	return 0;
}


The error(s):

main.cpp(16): error C2057: expected constant expression
main.cpp(17): error C2057: expected constant expression


It's referring to the const static member num_samples. This isn't making any sense to me. It's this exact problem that others have tried to explain to me in the past, but I can't wrap my head around it. Could someone explain it to me like I'm five? Thanks.

NOTE: my compiler doesn't support constexpr.
Last edited on
What version of Visual Studio are you using?
I'm using Visual Studio Community 2013, but I'm in the process of installing Visual Studio Community 2015...
The problem seems to be with this line const __int64 num_seconds_in_buffer = ((double)num_beats_per_bar / ((double)tempo / (double)num_seconds_in_minute));

Removing the casts the code compiles with VS2015.
Removing the casts the code compiles also with VS2013.
The code as originaly posted (without removing the casts), compiles cleanly with the Clang 3.7 with Microsoft CodeGen (v140_clang_3_7) toolchain (Visual Studio 2015).
https://blogs.msdn.microsoft.com/vcblog/2015/12/04/clang-with-microsoft-codegen-in-vs-2015-update-1/
Hi,

I made use of constexpr , and it works with the casts (I tested with both C and C++ casts):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <cstdint>

namespace Test {

    constexpr std::size_t num_channels = 2;
    constexpr std::size_t samplerate = 44100;
    constexpr std::size_t tempo = 120;
    constexpr std::size_t num_seconds_in_minute = 60;
    constexpr std::size_t num_beats_per_bar = 4;
//    constexpr ___int64 num_seconds_in_buffer = ((double)num_beats_per_bar / ((double)tempo / (double)num_seconds_in_minute));
    constexpr double num_seconds_in_buffer = (
                static_cast<double>(num_beats_per_bar) / ( static_cast<double>(tempo)
                                             /  static_cast<double>(num_seconds_in_minute) )

                );
//    typedef __int16 BitDepth;
    using BitDepth = uint16_t;

    class Buffer {
    public :
        Buffer() {}

        constexpr static std::size_t num_samples = num_seconds_in_buffer * samplerate * num_channels;
        BitDepth samples[num_samples];

        std::size_t get_num_samples() {
            return num_samples;
        }
    };
}

int main() {

    Test::Buffer buffer;

    std::cout << "Number of Samples is " << buffer.get_num_samples() << "\n";

    return 0;
}


You had __int64 when It should have been double on line 8 (your code), the current numbers work with an integer type and the casts but what if they change and you have a fraction?

I reckon this might work because constexpr is set in stone at compile time. Mind though I am using clang++ 3.7 with gcc5.3 c++14 on Linux , not sure of the vagaries of VS in terms of whether all the bugs are ironed out yet. I mean, I just don't know - I am a Linux person :+)

I didn't have a __int64 so I used std::size_t , but your type might be signed.

Any reason to not use static_cast<double>() instead of the C casts? I just tested with them: it worked.
Output:
Number of num_seconds_in_buffer is 2
Number of Samples is 176400



Edit: Whoops changed return type to double :+)

Hang on having a discombobulation numbers don't agree with my calculator

C++ was right the whole time, just the operator of the calculator was discombobulated !!

Hope this is all good for ya now !!

Last edited on
There is no difference between const std::int64_t a = 200 ; and constexpr std::int64_t a = 200 ;
In both, (a) is an integral constant expression.

There is a difference between const double c = double(a) / 2.3 ; and constexpr double c = double(a) / 2.3 ;
The former is ("as-if") evaluated at run-time; the latter is evaluated at compile-time and is a constant expression.

With -std=c++14 -pedantic errors
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <cstdint>

namespace Test
{
    const std::int64_t a = 200 ;
    int test_a[ a+2 ] {} ; // fine: a+2 is an integral constant expression

    constexpr std::int64_t b = 200 ;
    int test_b[ b+2 ] {} ; // fine: b+2 is an integral constant expression

    constexpr double c = double(a) / 2.3 ; // evaluated at compile-time
    // note: the compile-time evaluation of a floating point expressions may yield a result
    // that is different from the evaluation of the same operations on the same values at run-time.
    int test_c[ int(c) ] {}; // fine: int(c) is an integral constant expression

    const double d = double(a) / 2.3 ; // (semantically) evaluated at run-time
    int test_d[ int(d) ] {} ; // *** error: int(d) is not an integral constant expression
                              // note: the default GNU compiler is non-conforming wrt this
                              // with g++ / g++-compatible implementations, compile with
                              // -std=c++14 -pedantic errors to force conformance with standard C++
}

http://coliru.stacked-crooked.com/a/b18b3147208a8a34
JLBorges wrote:
The former is ("as-if") evaluated at run-time; the latter is evaluated at compile-time and is a constant expression.


Ok, I thought understood that, but I didn't realise it produced different results :+(

And it was wrong of me to suggest that might have been part of the problem.

However what about this part?

TheIdeasMan wrote:
You had __int64 when It should have been double on line 8 (your code), the current numbers work with an integer type and the casts but what if they change and you have a fraction?


Further, removing the casts to double would produce integer division. I know you weren't proposing that, but others were.

1
2
// with g++ / g++-compatible implementations, compile with
// -std=c++14 -pedantic errors to force conformance with standard C++ 


I compile with this these days, qmake adds a bunch of other stuff too:

clang++  -std=c++14 -Wall -W -Wextra -pedantic-errors -Wswitch-default -Wswitch-enum -Wunused -Wfloat-equal -Wconversion -Wzero-as-null-pointer-constant -Weffc++




// note: the compile-time evaluation of a floating point expressions may yield a result
// that is different from the evaluation of the same operations on the same values at run-time
.

Well, that's a bit of a worry :+| How does that come about? Noted that you say may , but I wonder how much of a difference? Would extending the type to long double, multi-precision or exact decimal make any difference? If a fix is needed that is. It may not be so bad if a type change fixes it, or if one of const or constexpr proves to be better than the other.

I have some code that has a heap of constexpr in the initialisations of crucial values: for some of them up to 13sf or possibly more are required to be accurate. If it's going to be an issue I might have to do some analysis to see just how precise these values have to be. Probably good to know anyway. The first few of these initial values go on to participate in dozens of other expressions. So far testing with one set of values seems to have worked, but I am not around to any serious & thorough testing yet. I have to investigate the best way of doing that.

IIRC, the reason why I used constexpr was that I had just read an article by Herb Sutter saying to use auto, constexpr and brace initialisation as much as possible.

If you have lots of spare time, here is the link to the manual:

http://www.icsm.gov.au/gda/gdatm/gdav2.3.pdf

I have worked on Chapter 4, page 20 of the pdf (pg15, the document) Vincenty Inverse.

Probably only have to look at that one page to see the sort of things that go on :+)

One quick example is the Lat & Long values. They are expressed to 5dp of 1 arc-second (<1mm in position), in radians that is 4.848e-11. probably want 3 or 4 more dp if one is to do calcs with those, so that 15sf.

Co-ordinates (ECEF Cartesian and Plane) are expressed to the millimetre with 10sf

Any way it's late my end, Thanks again for all your help.
> but I didn't realise it produced different results

The IS has this footnote:
Nonetheless, implementations are encouraged to provide consistent results, irrespective of whether the evaluation was performed during translation and/or during program execution.

It won't produce different results if the compile-time floating point environment is the same as the run-time floating point environment. These need not be the same if we are cross-compiling for a different hardware architecture. IEEE 754 floating point is widely adopted; so in most cases, this is not a concern.
Thanks to everyone for their input! Ultimately, I was able to resolve my problem!
Topic archived. No new replies allowed.