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?

5
  • 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. Commented Nov 12, 2011 at 23:34
  • @KerrekSB oh, I never knew that. You should write that as an answer. Commented Nov 12, 2011 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. Commented Nov 12, 2011 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. Commented Nov 12, 2011 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! Commented Nov 13, 2011 at 0:27

2 Answers 2

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.)

Sign up to request clarification or add additional context in comments.

Comments

1

This will compile successfully:

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.