2

I have this code:

constexpr int log2(const unsigned int x) {
    return x < 4 ? 1 : 1 + log2(x / 2);
}

int main() {
    bitset<log2(2)> foo;
    int bar[log2(8)];

    cout << log2(8) << endl;
}

This works fine in gcc: https://ideone.com/KooxoS

But when I try on I get these errors:

error C2975: _Bits: invalid template argument for std::bitset, expected compile-time constant expression
note: see declaration of _Bits
error C2131: expression did not evaluate to a constant
note: failure was caused by call of undefined function or one not declared constexpr
note: see usage of log2

Obviously log2 is constexpr so I assume this is just a bug in . Is there a way I can work around this bug?

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • 1
    Looks like visual studio issue. Try visual studio 2019, as they are often slightly behind in standard compliance. – Radosław Cybulski Jun 13 '19 at 14:27
  • 2
    if I rename this to log22 (or Log2) it compiles in VS2017, all i get is `warning C4101: 'bar': unreferenced local variable`, output prints 3. It looks like its picking up a standard lib one that is not constexpr? – Borgleader Jun 13 '19 at 14:27
  • 1
    @NathanOliver this is a bad duplicate I can get the same compilation error locally *without* `using namespace std;`. – Borgleader Jun 13 '19 at 14:51
  • Why is it that math functions aren't confined to the `std` namespace? – François Andrieux Jun 13 '19 at 14:52
  • @Borgleader Already reopened. – NathanOliver Jun 13 '19 at 14:53
  • @NathanOliver I'll leave my comment there in case anyone else is tempted to close it (someone else commented the same thing before and it got removed). – Borgleader Jun 13 '19 at 14:55
  • @FrançoisAndrieux To make life easier for the implementors they allow the `` headers to also let the names be in the global space. – NathanOliver Jun 13 '19 at 14:55
  • 1
    @FrançoisAndrieux Because [the whole situation is an absolute mess](https://developers.redhat.com/blog/2016/02/29/why-cstdlib-is-more-complicated-than-you-might-think/). See also https://stackoverflow.com/questions/11085916/why-are-some-functions-in-cmath-not-in-the-std-namespace – Max Langhof Jun 13 '19 at 14:55
  • @NathanOliver I guess I was more wondering where that exception is codified. Edit : Max's link seems to answer that question though. – François Andrieux Jun 13 '19 at 14:59
  • 1
    @Borgleader Great comment. That was the issue, thank you. I'll accept one of these answers shortly. – Jonathan Mee Jun 13 '19 at 15:18

2 Answers2

5

It looks like your project includes the standard std::log2 function which the compiler confuses with the your log2 function. This can happen even if you don't #include <cmath> because standard headers are allowed to include any other standard headers. This is also another example of using namespace std; backfiring.

One solution is to rename your constexpr function to something else :

#include <bitset>
#include <iostream>

using namespace std;

constexpr int logTwo(const unsigned int x) {
    return x < 4 ? 1 : 1 + logTwo(x / 2);
}

int main() {
    bitset<logTwo(2)> foo;
    int bar[logTwo(8)];

    cout << logTwo(8) << endl;
}

Demo

Edit : It seems that using namespace std; may be unrelated in this case. The standard log2 function may be available at the global namespace anyway.

François Andrieux
  • 28,148
  • 6
  • 56
  • 87
3

Obviously log2 is constexpr

A function being constexpr does not mean it can be always used to compute a compute-time value. When x >= 4, you are calling std::log2, which is not constexpr itself.

GCC implements them as such as an extension. See Is it a conforming compiler extension to treat non-constexpr standard library functions as constexpr?

Acorn
  • 24,970
  • 5
  • 40
  • 69