是否实例化了模板类的非模板朋友?

问题描述 投票:2回答:2

请考虑以下代码:

//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编译就很好(至少在msvc和gcc上)。为什么呢?这种功能是否仍然是非模板功能的一种特殊情况?

标准的哪些部分允许或阻止我这样做?

c++ templates language-lawyer friend friend-function
2个回答
1
投票

模板类中定义的非模板朋友功能是模板化实体。

摘自C ++ 20标准(13.1序言)

8模板化实体是

((8.1)-模板,

(8.2)-在模板中定义(6.2)或创建(6.7.7)的实体实体,

((8.3)-模板实体的成员,

(8.4)—作为模板实体的枚举的枚举,或

(8.5)-lambda表达式(7.5.5.1)的闭合类型出现在模板实体的声明

[注:局部类,局部变量,或定义的朋友函数在模板化实体中是模板化实体。 —尾注]

在需要时被实例化。所以在这个类中定义

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

[如果我尝试手动定义递减运算符(在算术之外,则会在--l上出现错误;

那些确实不是模板功能,因此您必须手动提供每个T的功能,此处为Foo的版本:

constexpr auto operator--(Foo& l, int)
{
    auto old = l; --l; return old;
}
© www.soinside.com 2019 - 2024. All rights reserved.