I have the following code:
class MyClass
{
static constexpr bool foo() { return true; }
void bar() noexcept(foo()) { }
};
I would expect that since foo()
is a static constexpr
function, and since it's defined before bar
is declared, this would be perfectly acceptable.
However, g++
gives me the following error:
error: ‘static constexpr bool MyClass::foo()’ called in a constant expression
This is...less than helpful, since the ability to call a function in a constant expression is the entire point of constexpr
.
clang++
is a little more helpful. In addition to an error message stating that the argument to noexcept
must be a constant expression, it says:
note: undefined function 'foo' cannot be used in a constant expression
note: declared here
static constexpr bool foo() { return true; }
^
So...is this a two-pass-compilation problem? Is the issue that the compiler is attempting to declare all the member functions in the class before any of them are defined? (Note that outside of the context of a class, neither compiler throws an error.) This surprises me; intuitively, I don't see any reason for static constexpr
member functions not to be useable in any and all constant expressions, inside the class or out.
As T.C. demonstrated with some links in a comment, the standard is not quite clear on this; a similar problem arises with trailing return types using
decltype(memberfunction())
.The central problem is that class members are generally not considered to be declared until after the class in which they're declared is complete. Thus, regardless of the fact that
foo
isstatic constexpr
and its declaration precedes that ofbar
, it cannot be considered "available" for use in a constant expression untilMyClass
is complete.As pointed out by Shafik Yaghmour, there is some attempt within the standard to avoid a dependency on the ordering of members within a class, and obviously allowing the example in the original question to compile would introduce an ordering dependency (since
foo
would need to be declared beforebar
). However, there is already a minor dependency on ordering, because althoughconstexpr
functions can't be called insidenoexcept
, anoexcept
expression itself might depend on an earlier declaration inside the class:(Note that this is not actually a violation of 3.3.7, since there is still only one correct program that is possible here.)
This behavior may actually be a violation of the standard; T.C. points out (in a comment below) that
foo
here should actually be looked up in the scope of the whole class. Both g++ 4.9.2 and clang++ 3.5.1 fail with an error whenbar
is declared first but compile with no errors or warnings whenfoo
is declared first. EDIT: clang++ trunk-revision 238946 (from shortly before the release of 3.7.0) does not fail whenbar
is declared first; g++ 5.1 still fails.Intriguingly, the following variation causes a "different exception specifier" with clang++ but not with g++:
According to the error, the
noexcept
specification for the declaration ofbar2
evaluates tonoexcept(false)
, which is then considered a mismatch fornoexcept(noexcept(MyClasss::foo2()))
.