Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;模板友元运算符重载_C++_Templates_Operator Overloading_Friend - Fatal编程技术网

C++ C++;模板友元运算符重载

C++ C++;模板友元运算符重载,c++,templates,operator-overloading,friend,C++,Templates,Operator Overloading,Friend,我的代码有什么问题 template<int E, int F> class Float { friend Float<E, F> operator+ (const Float<E, F> &lhs, const Float<E, F> &rhs); }; 模板 班级浮动 { 友元浮点运算符+(常量浮点和左、常量浮点和右); }; G++只是不断发出警告: float.h:7:警告:友元声明“float操作符+(常量float

我的代码有什么问题

template<int E, int F>
class Float
{
 friend Float<E, F> operator+ (const Float<E, F> &lhs, const Float<E, F> &rhs);
};
模板
班级浮动
{
友元浮点运算符+(常量浮点和左、常量浮点和右);
};
G++只是不断发出警告:

float.h:7:警告:友元声明“float操作符+(常量float&,常量float&)”声明非模板函数

float.h:7:警告:(如果这不是您想要的,请确保函数模板已经声明并添加到函数名称之后)-Wno非模板朋友禁用此警告

正如警告说明中提到的,我试图在函数名后添加
,但是g++给了我一个错误


我用clang++编译了代码,很好,没有任何警告。

您需要完全按照警告所说的操作:

template<int E, int F>
Float<E, F> operator+ (const Float<E, F> &lhs, const Float<E, F> &rhs);

template<int E, int F>
class Float
{
 friend Float<E, F> operator+<> (const Float<E, F> &lhs, const Float<E, F> &rhs);
};
模板
浮点运算符+(常量浮点和左侧、常量浮点和右侧);
模板
班级浮动
{
友元浮点运算符+(常量浮点和左、常量浮点和右);
};

这声明了操作符模板的完全专门化,即类模板的特定实例的朋友。在对这个问题的评论中,UncleBens善意地提供了这一问题如此复杂的原因

这只是对语言中一个棘手方面的警告。当您声明
friend
函数时,它不是声明所在类的成员。为了方便起见,您可以在那里定义它,但它实际上属于名称空间

在类模板中声明非模板的友元函数,仍然在命名空间中声明非模板函数。它既不是类的成员,也不是模板。但是,它是由类模板生成的

从模板生成非模板函数有点模糊。例如,不能在
块之外添加该函数的声明。因此,您还必须在
块中定义它,这是有意义的,因为类模板将生成它

关于friends的另一个棘手问题是
类Float{}
中的声明没有在名称空间中声明函数。您只能通过依赖于参数的含义重载解析来找到它,即指定参数的类型为
Float
(或引用或指针)。这不是
操作符+
的问题,因为它可能会被重载,并且除了使用用户定义的类型外,永远不会调用它

对于一个潜在问题的示例,假设您有一个转换构造函数
Float::Float(Bignum const&)
。但是
Bignum
没有
运算符+
。(很抱歉,是人为的例子。)您想依靠
运算符+(Float-const&,Float-const&)
进行
Bignum
加法。现在
my_bignum+3
将不会编译,因为两个操作数都不是
Float
,因此它找不到
friend
函数

只要所讨论的函数是一个
操作符
,就可能不需要担心

或者,您也可以将
朋友
更改为模板。在这种情况下,它必须在
类{}
块之外定义,并在它之前声明,而不需要在内部声明和定义

template//现在这是一个模板!
浮点运算符+(常量浮点和左侧、常量浮点和右侧);
模板
班级浮动
{
//推断参数E和F-此参数命名运算符+。
友元浮点运算符+(常量浮点和左、常量浮点和右);
};

这是一个相当古老的主题,但我认为声明运算符的最简单方法是在Float类中定义它

template<int E, int F>
class Float
{
public:
    friend Float operator+ (const Float &lhs, const Float &rhs)
    {
        // Whatever you need to do.
    }
};
模板
班级浮动
{
公众:
友元浮点运算符+(常量浮点和左侧、常量浮点和右侧)
{
//不管你需要做什么。
}
};
语法更容易编写和理解,并且工作原理完全相同(除了它将内联),它将不是一个成员函数

MSDN:在类声明中定义的友元函数不在封闭类的范围内考虑;它们在文件范围内


您可能想阅读@Potatoswatter:friend声明声明了一个特定的专门化,它是类的朋友,不是吗?事实上,我刚刚测试了@sbi的代码,它可以与我的g++一起使用。@Zifei:这个代码段可以,但它需要更改函数的定义。(很抱歉,我没有注意到函数形式的更改。)感谢您友好的回答。在定义
操作符+
模板之前,您是否也应该向前声明
Float
类?@ValerioFormato Yes;我没有包括它,因为考虑到他的问题的上下文,Zifei肯定已经这样做了。不,在
操作符+
的情况下,通常最简单和最好的方法是将
操作符+=
作为一个成员来实现,然后将
操作符+
作为一个非成员非朋友来实现。这可以确保定义了两个运算符,并且它们的行为一致。
template<int E, int F>
class Float
{
public:
    friend Float operator+ (const Float &lhs, const Float &rhs)
    {
        // Whatever you need to do.
    }
};