0

classes seem to have a problem caling their constexpr member functions in another constexpr context. For example in this piece of code that I proposed in an earlier question this behaviour can be seen:

struct Foo {
    constexpr static bool TRUE() {
        return true;
    }
    static_assert(Foo::TRUE(), ""); //ERROR
};

As the static_assert depends on Foo::TRUE() compilation fails because Foo::TRUE() isn't fully resolved in this context yet.


So how does adding a single template to Foo solve the whole issue?:

template<int x>
struct Foo {
    constexpr static bool TRUE() {
        return true;
    }
    static_assert(Foo::TRUE(), ""); //compiles fine
};

After all these insights this code here shouldn't compile - yet it does. It doesn't seem to make sense, as there isn't any difference to the non-template version.

Also there should always be equally many TRUE()-functions and static_assert-calls as there are Foo<> classes, so the same dependency problem should occur when compiling.


I am using Visual Studio 17 Community Version 15.9.0 - thanks for any help!

Stack Danny
  • 7,754
  • 2
  • 26
  • 55

1 Answers1

2

This is CWG 1626:

The Standard should make clear that a constexpr member function cannot be used in a constant expression until its class is complete. For example:

template<typename T> struct C {
  template<typename T2> static constexpr bool _S_chk() {
    return false;
  }
  static const bool __value = _S_chk<int>();
}; 

C<double> c;

Current implementations accept this, although they reject the corresponding non-template case:

struct C {
  static constexpr bool _S_chk() { return false; }
  static const bool __value = _S_chk();
};

C c; 

Presumably the template case should be handled consistently with the non-template case.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • so according to the standard the templated `Foo` shouldn't work either, yet the implementation allow it? I see – Stack Danny Dec 05 '18 at 14:13
  • What?? This proposal is from 2013, quite old comparing to the current standard. Especially with `if constexpr` in C++17, this restriction will cause a lot of pain to metaprogramming. I mean, the simplest way to compute a type with static branching is to write a function with `auto` return then branching in the function body. If this proposal finally integrated into the standard, such static function must be moved to outside the template... – llllllllll Dec 05 '18 at 14:27
  • @liliscent It's not a proposal, it's an open core language issue. – Barry Dec 05 '18 at 14:33
  • @Barry Yeah, I meant this issue. Just there is a suggestion in the issue to forbid this kind of use in template. It will cause much inconvenience. – llllllllll Dec 05 '18 at 14:38
  • @liliscent: It actually won't change much. `if constexpr` means that you're inside of a function. And function definitions are considered to appear just after the class is complete, so you ought to be able to call `constexpr` members just fine. – Nicol Bolas Dec 05 '18 at 15:52
  • @Nicol For example, you can no longer interleave static function with `using` alias to store the type result, nor can you add nontrivial `static_assert` check in a natural location, which will at least make the code less readable. What is weird is that member function in template is instantiated on-demand, it’s a different story with the non-template case, this core issue doesn’t make sense to me. – llllllllll Dec 05 '18 at 16:44