6

I try to have a member function require a static constexpr boolean member to be true. This would be very helpful to DRY a quite complex requirement. And I do not quire get the reason why the compiler won't let me.

Minimal example with slightly less complex requirement:

template <typename T>
struct Foo
{
    static constexpr bool isInt = std::integral<T>;
    void bar() requires (isInt);
    void goo() requires std::integral<T>;
};

template <typename T>
void Foo<T>::bar() requires (Foo<T>::isInt) // error: out-of-line definition of 'bar' does not match any declaration in 'Foo<T>' x86-64 clang 14.0.0 #1
{
    // ...
}

template <typename T>
void Foo<T>::goo() requires std::integral<T> // ok
{
    // ...
}

Is this because isInt is declared inside the same class? Or do I have some kind of syntax error?

Aamir
  • 1,974
  • 1
  • 14
  • 18
tirofes
  • 63
  • 2
  • Seems like just an msvc problem. clang and gcc happily accept it (as they should). – Barry Jan 06 '23 at 20:16
  • @Barry As commented in the code snippet, [Clang currently does not](https://godbolt.org/z/9dsK1seT7). As per [the answer from user17732522](https://stackoverflow.com/a/75035712/440558) it seems to be a bug that is about to be fixed in future releases. – Some programmer dude Jan 06 '23 at 20:29
  • @Someprogrammerdude [As I said, it currently does.](https://godbolt.org/z/GqsWhhMK5) – Barry Jan 06 '23 at 20:32
  • @Barry Ah, you're using the *trunk* build of Clang, which is not yet part of a Clang release. Comment updated. – Some programmer dude Jan 06 '23 at 20:32

2 Answers2

3

There is a question of whether or not your requires clauses in the in-class declaration and out-of-class definition are equivalent (or functionally equivalent).

But regardless of the answer to that question, the easiest solution is to simply use the exact same token sequence, which will be certain to be equivalent:

template <typename T>
void Foo<T>::bar() requires (isInt)
{
    // ...
}

However, current Clang releases don't accept any variations I try to name the static member, especially not those using the same token sequence in both declaration and definition. At least that last part is definitively a bug.

But on current Clang trunk all variations are accepted, indicating that this is a recently fixed bug.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • Oh well. I tested it with Clang 14, Clang 15 and MSVC - lucky me :D Thanks for restoring my C++ sanity. GCC 12.2 can handle this correctly btw. – tirofes Jan 08 '23 at 16:03
1

Seems like an MSVC bug. Here's a workaround:

#include <concepts>

template <class T>
concept isInt = std::integral<T>;

template <typename T>
struct Foo
{
    void bar() requires (isInt<T>);
};

template <typename T>
void Foo<T>::bar() requires (isInt<T>) 
{
}

https://godbolt.org/z/h6enoGqG6

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93