c++ - 模板类的非模板友元是否被实例化?

标签 c++ templates language-lawyer friend friend-function

考虑以下代码:

//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/

相关文章:

c++ - 与前向声明的类声明友元是否合法?

c++ - 推导给定参数类型的选定重载函数类型

c++ - 通过初始化列表实例化抽象类

c++ - 用于对象检测的 dlib 标记 - 仅检测 60%

c++ - 在Vulkan中使法线贴图工作时遇到一些问题

c++ - 8192位异或加密?

c++ - 匹配别名模板作为模板参数

c++ - 模板父类(super class)的静态成员定义

c++ - 初始化器究竟是什么时候被临时销毁的?

c++ - 可变参数模板仅在前向声明时编译