Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change constexpr object member using method fail

I'm trying to change the value of a constexpr object member via a method but i don't understand why it's not working in this specific case :

#include <iostream>

struct test
{
    int m_counter = 0;

    constexpr test()
    {
        m_counter++;
        m_counter++;
        increment();
        increment();
        increment();
    }

    constexpr void increment()
    {
        m_counter++;   
    }

    constexpr int value() const
    {
        return m_counter;
    }
};

template<int value>
constexpr void check()
{
    std::cout << value << std::endl;
}

// constexpr test t; // value = 3, why ?

int main()
{
    constexpr test t; // value = 5, ok
    check<t.value()>();
}

I don't understand why value is 3 when i create object in global scope. msvc and clang display 5 in both cases but not gcc. Who is wrong?

like image 579
ads00 Avatar asked Mar 14 '17 10:03

ads00


1 Answers

This seems to be a g++ bug, reproducible from g++ 5.1 up to g++ 7.0. I think it is a bug because the behavior seems nonsensical. I played around with the snippet and I believe that the compiler only executes the first increment() call if the variable is global, disregarding the other invocations:

constexpr test()
{
    m_counter++; // executed
    m_counter++; // executed
    increment(); // executed
    increment(); // NOT executed
    increment(); // NOT executed
}

// [...] will print 3

constexpr test()
{
    m_counter++; // executed
    m_counter++; // executed
    increment(); // executed
}

// [...] will print 3

constexpr test()
{
    m_counter++; // executed
    m_counter++; // executed
}

// [...] will print 2

constexpr test()
{
    m_counter++; // executed
    m_counter++; // executed
    increment(); // executed
    increment(); // NOT executed
    increment(); // NOT executed
    increment(); // NOT executed
    increment(); // NOT executed
    increment(); // NOT executed
}

// [...] will print 3

Basically, only one increment() inside the constructor will be executed. Adding more increment() calls has no effect. Adding more m_counter++ instructions will however work properly.

constexpr test()
{
    m_counter++; // executed 
    m_counter++; // executed
    increment(); // executed
    increment(); // NOT executed
    m_counter++; // executed
    m_counter++; // executed
    increment(); // NOT executed
    increment(); // NOT executed
}

// [...] will print 5

I reported this on the g++ bug tracker as as bug #80039.

like image 196
Vittorio Romeo Avatar answered Nov 10 '22 02:11

Vittorio Romeo