6

If I try to compile the following C++0x code, I get an error:

template<int n> struct foo { };

struct bar {
    static constexpr int number() { return 256; }

    void function(foo<number()> &);
};

With gcc 4.6.1, the error message is:

test.cc:6:27: error: ‘static constexpr int bar::number()’ used before its definition
test.cc:6:28: note: in template argument for type ‘int’

With clang 2.8, the error message is:

test.cc:6:20: error: non-type template argument of type 'int' is not an integral
      constant expression
        void function(foo<number()> &);
                          ^~~~~~~~
1 error generated.

If I move the constexpr function to a base class, it works on gcc, and gives the same error message on clang:

template<int n> struct foo { };

struct base {
    static constexpr int number() { return 256; }
};

struct bar : base {
    void function(foo<number()> &);
};

Is the code wrong, or is it a limitation or bug on gcc 4.6's implementation of C++0x? If the code is wrong, why is it wrong, and which clauses of the C++11 standard say it is incorrect?

CesarB
  • 43,947
  • 7
  • 63
  • 86
  • 2
    Hmm.. I think we just discussed this earlier: inline function definitions are treated as though they were defined *just after* the class definition; so inside the class definition they're not yet available. Note that you can always say `static const int number = 256;` or `static constexpr int number = 256;` instead. – Kerrek SB Nov 12 '11 at 23:34
  • @KerrekSB oh, I never knew that. You should write that as an answer. – Seth Carnegie Nov 12 '11 at 23:37
  • @KerrekSB: AFAIK, if I use `static const int number = 256;`, I also need a `const int bar::number;`, which would wastefully add 4 useless bytes to `.data`. Using an inline function prevents that. I have no idea if that is also the case for `static constexpr int number = 256;`, however. – CesarB Nov 12 '11 at 23:46
  • 1
    @CesarB: No, not necessarily. As long as you never attempt to take the address, you don't actually need to provide an implementation of a static constant. – Kerrek SB Nov 12 '11 at 23:57
  • @KerrekSB: looking at this C++0x draft I have, I see at [class.static.data]: "The member shall still be defined in a namespace scope if it is odr-used [...]", and at [basic.def.odr]: "[...] A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression and the lvalue-to-rvalue conversion is immediately applied. [...]". Looks like you are right, depending on what [expr.const] and [conv.lval] say. Even better, this way does it not need any `#ifndef` for MSVC! – CesarB Nov 13 '11 at 00:27

2 Answers2

5

In C++, inline definitions of member functions for a class are only parsed after every declaration in the class is parsed. Therefore, in your first example, the compiler can't see the definition of number() at the point where function() is declared.

(No released version of clang has support for evaluating constexpr functions, so none of your testcases will work there.)

servn
  • 3,049
  • 14
  • 8
1

I've got a simillar error with the following code:

struct Test{
     struct Sub{constexpr Sub(int i){}};
    static constexpr Sub s=0;
};

"error: 'constexpr Test::Sub::Sub(int)' called in a constant expression" on gcc 4.7.1. while This will compile successfully:

struct Sub{constexpr Sub(int i){}};
struct Test{
    static constexpr Sub s=0;
};
Pony279
  • 403
  • 1
  • 6
  • 12
  • 4
    Please only provide an answer if you what you are contributing will *answer* the question the user is posing. What you have posted is considered more of a comment, which you will gain the privilege to post as you use the site more. Thanks for joining S.O. and welcome. – Liftoff Dec 08 '12 at 06:54