C++20 out-of-class definition in a template class

ProXicT

Up until C++20 standard of C++, when we wanted to define an out-of-class operator which uses some private members of a template class, we'd use a construct similar to this:

template <typename T>
class Foo;

template <typename T>
constexpr bool operator==(T lhs, const Foo<T>& rhs);

template <typename T>
class Foo {
public:
    constexpr Foo(T k) : mK(k) {}

    constexpr friend bool operator==<T>(T lhs, const Foo& rhs);

private:
    T mK;
};

template <typename T>
constexpr bool operator==(T lhs, const Foo<T>& rhs) {
    return lhs == rhs.mK;
}

int main() {
    return 1 == Foo<int>(1) ? 0 : 1;
}

Since C++20, however, we can omit the out-of-class declaration, thus also the forward declaration, so we can get away with just:

template <typename T>
class Foo {
public:
    constexpr Foo(T k) : mK(k) {}

    constexpr friend bool operator==<T>(T lhs, const Foo& rhs);
private:
    T mK;
};

template <typename T>
constexpr bool operator==(T lhs, const Foo<T>& rhs) {
    return lhs == rhs.mK;
}

Demo

Now, my question is, what part of C++20 allows us to do so? And why wasn't this possible in earlier C++ standards?


As it was pointed out in the comments, clang doesn't accept this code presented in the demo, which suggests this might actually be a bug in gcc.

I filed a bug report on gcc's bugzilla

Richard Smith

GCC has a bug.

Name lookup is always performed for template names appearing before a <, even when the name in question is the name being declared in a (friend, explicit specialization, or explicit instantiation) declaration.

Because the name operator== in the friend declaration is an unqualified name and is subject to name lookup in a template, the two-phase name lookup rules apply. In this context, operator== is not a dependent name (it's not part of a function call, so ADL does not apply), so the name is looked up and bound at the point where it appears (see [temp.nondep] paragraph 1). Your example is ill-formed because this name lookup finds no declaration of operator==.

I would expect GCC is accepting this in C++20 mode due to P0846R0, which permits (for example) operator==<T>(a, b) to be used in a template even if no prior declaration of operator== as a template is visible.

Here's an even more interesting testcase:

template <typename T> struct Foo;

#ifdef WRONG_DECL
template <typename T> bool operator==(Foo<T> lhs, int); // #1
#endif

template <typename T> struct Foo {
  friend bool operator==<T>(Foo<T> lhs, float); // #2
};

template <typename T> bool operator==(Foo<T> lhs, float); // #3
Foo<int> f;

With -DWRONG_DECL, GCC and Clang agree that this program is ill-formed: unqualified lookup for the friend declaration #2, in the context of the template definition, finds the declaration #1, which doesn't match the instantiated friend of Foo<int>. Declaration #3 is not even considered, because unqualified lookup in the template doesn't find it.

With -UWRONG_DECL, GCC (in C++17 and earlier) and Clang agree that this program is ill-formed for a different reason: unqualified lookup for operator== on line #2 finds nothing.

But with -UWRONG_DECL, GCC in C++20 mode appears to decide that it's OK that unqualified lookup for operator== in #2 fails (presumably due to P0846R0), and then appears to redo the lookup from the template instantiation context, now finding #3, in violation of the normal two-phase name lookup rule for templates.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

C++20 out-of-class definition in a template class

From Dev

C++ template static integer constants: out of class definition

From Dev

Out-of-class definition of function of specialized inner class template?

From Dev

C++ - Default arguments cannot be added to an out-of-line definition of a member of a class template

From Dev

What kind of class template definition is this?

From Dev

Partial Template specialization definition outside of class definition

From Dev

Partial Template specialization definition outside of class definition

From Dev

inner class method definition outside of a template class

From Dev

C++ member function definition class prefix shortcut (also template)

From Dev

Template class array definition is not type name, static or enumerator C++

From Dev

C++ member function definition class prefix shortcut (also template)

From Dev

Definition of class in c++

From Dev

Specialization of template <class T> definition of template <class T>

From Dev

How can I use different definition of class for different template type in C++? (Class Overloading?)

From Dev

Inheriting from a template class using the inheriting class with C++20 concepts

From Java

Should a definition inside template class be instantiated if it is not used?

From Dev

Wrong definition of function in template inherited class

From Dev

How to separate definition and declaration of child template class

From Dev

Friend template function in-class definition

From Dev

Template specialization of constructor within class definition

From Dev

Definition of private weak_ptr in template class

From Dev

Class definition conventions in C#

From Dev

Out-of-line definition of base class' nested class

From Dev

Define operator[]() (array subscription) for template class outside of class definition

From Dev

Knocking out a class template constructor depending on class template parameter

From Dev

Function pointer definition inside a class template based on the template variable arguments

From Dev

How to separate definition from the declaration for a class template using 'extern' in C++11 in a library (dll, so,..)

From Dev

C++, partial specialization of 2-argument class template: unable to match function definition to an existing declaration

From Dev

Import c enum to c++ class definition

Related Related

  1. 1

    C++20 out-of-class definition in a template class

  2. 2

    C++ template static integer constants: out of class definition

  3. 3

    Out-of-class definition of function of specialized inner class template?

  4. 4

    C++ - Default arguments cannot be added to an out-of-line definition of a member of a class template

  5. 5

    What kind of class template definition is this?

  6. 6

    Partial Template specialization definition outside of class definition

  7. 7

    Partial Template specialization definition outside of class definition

  8. 8

    inner class method definition outside of a template class

  9. 9

    C++ member function definition class prefix shortcut (also template)

  10. 10

    Template class array definition is not type name, static or enumerator C++

  11. 11

    C++ member function definition class prefix shortcut (also template)

  12. 12

    Definition of class in c++

  13. 13

    Specialization of template <class T> definition of template <class T>

  14. 14

    How can I use different definition of class for different template type in C++? (Class Overloading?)

  15. 15

    Inheriting from a template class using the inheriting class with C++20 concepts

  16. 16

    Should a definition inside template class be instantiated if it is not used?

  17. 17

    Wrong definition of function in template inherited class

  18. 18

    How to separate definition and declaration of child template class

  19. 19

    Friend template function in-class definition

  20. 20

    Template specialization of constructor within class definition

  21. 21

    Definition of private weak_ptr in template class

  22. 22

    Class definition conventions in C#

  23. 23

    Out-of-line definition of base class' nested class

  24. 24

    Define operator[]() (array subscription) for template class outside of class definition

  25. 25

    Knocking out a class template constructor depending on class template parameter

  26. 26

    Function pointer definition inside a class template based on the template variable arguments

  27. 27

    How to separate definition from the declaration for a class template using 'extern' in C++11 in a library (dll, so,..)

  28. 28

    C++, partial specialization of 2-argument class template: unable to match function definition to an existing declaration

  29. 29

    Import c enum to c++ class definition

HotTag

Archive