考虑以下代码:
//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;
}
如果我尝试“手动”定义后递减运算符(在算术之外),我会在 --l;
上收到错误,因为前递减运算符递减运算符未定义。由于模板类的非模板友元显然不被视为模板函数,因此我期望相同的行为。
但事实上,代码对于 C++17 编译得很好(至少在 msvc 和 gcc 上)。为什么会这样?这种函数是仍然被实例化的非模板函数的特例吗?
标准的哪些部分允许或阻止我做这样的事情?
最佳答案
模板类中定义的非模板友元函数是模板化实体。
摘自 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]
它在需要时被实例化。所以在这个类定义中
//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
未在类 Foo
中声明。
关于c++ - 模板类的非模板友元是否被实例化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60512385/