2

I have the following piece of code which represents an actual bigger piece of code:

#include <iostream>
using namespace std;

template<size_t N> class A {
    public:
        static constexpr size_t getN() {return N;}
};

template<size_t N> class B {
    public:
        void print() { cout << "B created: " << N << '\n';}
};

template <class T> class C {
    public:
        void set(T* a) {
            t_ptr = a;
        }

        void create() {
            constexpr int m = t_ptr->getN();
            B<m> b;
            b.print();
        }

    private:
        T* t_ptr;
};

int main() {
   constexpr int n = 2;
   A<n> a;
   C<A<n> > c;
   c.set(&a);
   c.create();
}

Compiling with g++ -o main main.cpp -std=c++11 and GCC/G++ 4.8.3 the expected output is received: B created: 2

However, with GCC/G++ 4.9.1 the code does not compile, output:

main.cpp: In member function ‘void C<T>::create()’:
main.cpp:27:15: error: the value of ‘m’ is not usable in a constant expression
             B<m> b;
               ^
main.cpp:26:27: note: ‘m’ used in its own initializer
             constexpr int m = t_ptr->getN();
                           ^
main.cpp:27:16: error: the value of ‘m’ is not usable in a constant expression
             B<m> b;
                ^
main.cpp:26:27: note: ‘m’ used in its own initializer
             constexpr int m = t_ptr->getN();
                           ^
main.cpp:27:19: error: invalid type in declaration before ‘;’ token
             B<m> b;
                   ^
main.cpp:28:15: error: request for member ‘print’ in ‘b’, which is of non-class type ‘int’
             b.print();
               ^

This is caused by a known bug in GCC 4.9: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59937 and in this older thread https://gcc.gnu.org/ml/gcc-bugs/2013-11/msg00067.html the usage of extern is proposed as a workaround. However, I am not able to get this workaround working.

Could you guys help me to make this code compile in GCC 4.9? Thank you!

Ryan Haining
  • 35,360
  • 15
  • 114
  • 174
Javi
  • 3,440
  • 5
  • 29
  • 43

1 Answers1

3

Since this is not constexpr the access to this->t_ptr is not either.

clang's error is a bit more helpful

implicit use of 'this' pointer is only allowed within the
    evaluation of a call to a 'constexpr' member function

Referring to:

N3690 5.19/2 (emphasis added)

A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:

this, except in a constexpr function or a constexpr constructor that is being evaluated as part of e;

Calling the static member function via the typename works

constexpr int m = T::getN();
Ryan Haining
  • 35,360
  • 15
  • 114
  • 174
  • The code shown above compiles and works in GCC 4.8.3 so it is not a problem of constness, but a GCC bug. However I understand your point. Does that mean that GCC 4.8 is wrong? – Javi Jan 15 '15 at 10:07
  • 1
    @JaviV it seems that way. It wouldn't be the first time something like this happened. There's an older gcc in the C++0x line that allowed `auto i = "hello", j = 0;` but this kind of code doesn't work in newer versions. Constness has nothing to do with it, it's all about constant expressions. – Ryan Haining Jan 15 '15 at 15:28