Созданы ли не шаблонные друзья шаблонных классов? - PullRequest
2 голосов
/ 03 марта 2020

Рассмотрим следующий код:

//Allows to automatically define post in/de-crement operators from their pre- version
template<typename T>
struct Arithmetic
{
    //Not a template?
    friend constexpr auto operator++(T& l, int)
    { auto old = l; ++l; return old; }


    friend constexpr auto operator--(T& l, int)
    { auto old = l; --l; return old; }
};

//Only defines increment
struct Foo : Arithmetic<Foo>
{
    int val;
    Foo& operator++() { ++val; return *this; }
};


int main(int argc, char* argv[])
{
    Foo f;
    f.val = 12;
    ++f;
    f++;

    return 0;
}

Если бы я попытался определить оператор пост-декремента «вручную» (за пределами Arithmetic), я получил бы ошибку на --l;, потому что пред Оператор -определения не определен. Поскольку не шаблонные друзья шаблонных классов, по-видимому, не считаются шаблонными функциями, я ожидал бы того же поведения.

Но на самом деле код прекрасно компилируется для C ++ 17 (по крайней мере, для msv c и г cc). Почему это так? Является ли этот тип функции конкретным c случаем не шаблонной функции, которая все еще создается?

Какие части стандарта позволяют или запрещают мне делать такие вещи?

Ответы [ 2 ]

3 голосов
/ 03 марта 2020

Не шаблонная дружественная функция, определенная в шаблонном классе, является шаблонной сущностью.

Из стандарта C ++ 20 (13.1 Преамбула)

8 Шаблонный объект - это

(8.1) - шаблон,

(8.2 ) - объект, определенный (6.2) или созданный (6.7.7) в шаблонном объекте,

(8.3) - член шаблонного объекта,

(8.4) - перечислитель для перечисление, являющееся шаблонной сущностью, или

(8.5) - тип закрытия лямбда-выражения (7.5.5.1), появляющийся в объявлении шаблонной сущности

[Примечание: A локальный класс, локальная переменная или функция друга, определенная в шаблонном объекте, является шаблонным объектом . - конец примечания]

Он создается, когда это требуется. Таким образом, в этом определении класса

//Only defines increment
struct Foo : Arithmetic<Foo>
{
    int val;
    Foo& operator++() { ++val; return *this; }
};

шаблонная сущность

friend constexpr auto operator--(T& l, int)
{ auto old = l; --l; return old; }

не создается.

В случае, когда функция друга объявлена ​​только в классе шаблона struct Arithmetic и определяется вне класса для его специализации, тогда компилятор выдаст ошибку, потому что оператор --l не объявлен в class Foo.

0 голосов
/ 03 марта 2020

Если бы я попытался определить оператор пост-декремента «вручную» (вне Arithmeti c), я бы получил ошибку на --l;

Это действительно не шаблонные функции, поэтому вы должны вручную предоставить функцию для каждой T, здесь версия для Foo:

constexpr auto operator--(Foo& l, int)
{
    auto old = l; --l; return old;
}
...