模板 类 的非模板朋友是否被实例化?
Are non-template friends of template classes instantiated?
考虑以下代码:
//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;
}
如果我尝试定义 post-递减运算符 "manually"(在 Arithmetic
之外),我会在 --l;
上出现错误,因为预递减运算符未定义。由于模板 类 的非模板朋友显然不被视为模板函数,我希望有相同的行为。
但实际上,代码编译适用于 C++17(至少在 msvc 和 gcc 上)。为什么呢?这种函数是非模板函数的一个特例,它仍然被实例化吗?
标准的哪些部分允许或阻止我做这样的事情?
If I tried to define the post-decrement operator "manually" (outside of Arithmetic), I would get an error on --l
;
这些确实不是模板函数,因此您必须手动为每个 T
提供函数,这里是 Foo
的版本:
constexpr auto operator--(Foo& l, int)
{
auto old = l; --l; return old;
}
在模板中定义的非模板友元函数 class 是模板化实体。
来自 C++ 20 标准(13.1 序言)
8 A templated entity is
(8.1) — a template,
(8.2) — an entity defined (6.2) or created (6.7.7) in a templated
entity,
(8.3) — a member of a templated entity,
(8.4) — an enumerator for an enumeration that is a templated entity,
or
(8.5) — the closure type of a lambda-expression (7.5.5.1) appearing in
the declaration of a templated entity
[Note: A local class, a local variable, or a friend function defined
in a templated entity is a templated entity. —end note]
需要的时候实例化。所以在这个 class 定义中
//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; }
未实例化。
如果 friend 函数仅在模板 class struct Arithmetic
中声明并且在 class 之外定义以用于其特化,则编译器将发出错误,因为运算符--l
未在 class Foo
中声明。
考虑以下代码:
//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;
}
如果我尝试定义 post-递减运算符 "manually"(在 Arithmetic
之外),我会在 --l;
上出现错误,因为预递减运算符未定义。由于模板 类 的非模板朋友显然不被视为模板函数,我希望有相同的行为。
但实际上,代码编译适用于 C++17(至少在 msvc 和 gcc 上)。为什么呢?这种函数是非模板函数的一个特例,它仍然被实例化吗?
标准的哪些部分允许或阻止我做这样的事情?
If I tried to define the post-decrement operator "manually" (outside of Arithmetic), I would get an error on
--l
;
这些确实不是模板函数,因此您必须手动为每个 T
提供函数,这里是 Foo
的版本:
constexpr auto operator--(Foo& l, int)
{
auto old = l; --l; return old;
}
在模板中定义的非模板友元函数 class 是模板化实体。
来自 C++ 20 标准(13.1 序言)
8 A templated entity is
(8.1) — a template,
(8.2) — an entity defined (6.2) or created (6.7.7) in a templated entity,
(8.3) — a member of a templated entity,
(8.4) — an enumerator for an enumeration that is a templated entity, or
(8.5) — the closure type of a lambda-expression (7.5.5.1) appearing in the declaration of a templated entity
[Note: A local class, a local variable, or a friend function defined in a templated entity is a templated entity. —end note]
需要的时候实例化。所以在这个 class 定义中
//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; }
未实例化。
如果 friend 函数仅在模板 class struct Arithmetic
中声明并且在 class 之外定义以用于其特化,则编译器将发出错误,因为运算符--l
未在 class Foo
中声明。