C++ 接受类参数的友元函数的尾部返回类型
有关以下代码:C++ 接受类参数的友元函数的尾部返回类型,c++,friend-function,C++,Friend Function,有关以下代码: using std::string; class person { private: string fname, lname; double salary; public: person(string, string, double); // ctor declaration ~person(); // dtor declaration double operator+(person); friend auto salary_bu
using std::string;
class person
{
private:
string fname, lname;
double salary;
public:
person(string, string, double); // ctor declaration
~person(); // dtor declaration
double operator+(person);
friend auto salary_burden(person x, person y) -> decltype(x+y); // salary burden of two employees
};
我在y
下面的decltype
中看到了一个红色的波形,Intellisense说不能转换为不完整的类“person”
这是怎么回事
注:方法(包括系数和数据系数)的定义在不同的翻译单位中。我想这不是这里错误的原因。问题在于,即使
decltype
的操作数可能是不完整的类型,也不适用于构成充当decltype
操作数的prvalue的子表达式
decltype(x+y);
相当于
decltype(operator+(x, y));
但是person
在它自己的定义中是不完整的。您可以通过将operator+
定义为:
double operator+(person const&);
问题是,即使
decltype
的操作数可能是不完整的类型,也不适用于构成充当decltype
操作数的prvalue的子表达式
decltype(x+y);
相当于
decltype(operator+(x, y));
但是person
在它自己的定义中是不完整的。您可以通过将operator+
定义为:
double operator+(person const&);
您可能会发现一些有趣的注意事项:
#include <string>
#include <iostream>
namespace humans
{
class person
{
private:
// certainly never write using namespace::thing in header files.
// if you are going to be using a type, do it in a very confined scope, in a cpp file
std::string fname, lname;
double salary;
public:
person(std::string, std::string, double); // ctor declaration
// you neither need or want a destructor for this class.
// if you define a destructor, you must also define copy & assignment
// operators. See rule of 5, 3 or none.
// define a way to see the salary
double get_salary() const { return salary; }
// there is no such thing as a person plus a person.
// avoid nonsensical mathematical abstractions
// double operator+(person);
};
// let's also provide a free function to get_salary, because it can be useful in ADL
auto get_salary(person const & p) -> decltype(p.get_salary())
{
return p.get_salary();
}
// salary_burden does not need to be a friend now that we
// have a way to get the salary. Since there is a free function available
// in the namespace of person, we could abstract this function a little more!
auto salary_burden(person const& x, person const& y) -> decltype(get_salary(x) + get_salary(y))
{
return get_salary(x) + get_salary(y);
}
}
// indeed in c++17 we could also abstract this concept completely...
template<class...Things>
auto salary_burden(Things&&...things)
{
// here whatever namespace Things is in, this namespace will be
// searched for a function called get_salary(Thing[&&|const&|&])
return (get_salary(things) + ...);
}
namespace non_humans
{
struct robot{};
// note that a robot does not have a get_salary() member
auto get_salary(robot const&) -> double { return 5; }
}
int main()
{
auto alice = humans::person("alice", "the programmer", 20000);
auto bob = humans::person("bob", "the builder", 10000);
auto robby1 = non_humans::robot();
auto robby2 = non_humans::robot();
auto robby3 = non_humans::robot();
// calls salary_burden(person const& x, person const& y)
std::cout << salary_burden(alice, bob) << '\n';
// calls auto salary_burden(Things&&...things)
std::cout << salary_burden(alice, bob, robby1, robby2, robby3) << '\n';
}
#包括
#包括
命名空间人
{
班主任
{
私人:
//当然,永远不要在头文件中使用namespace::thing编写。
//如果要使用类型,请在非常有限的范围内使用cpp文件
std::字符串fname,lname;
双薪;
公众:
person(std::string,std::string,double);//构造函数声明
//这个类既不需要也不需要析构函数。
//如果定义析构函数,还必须定义复制和赋值
//运算符。请参见第5、3或无规则。
//定义查看薪资的方式
double get_salary()常量{return salary;}
//没有一个人加一个人这样的事情。
//避免无意义的数学抽象
//双操作员+(人);
};
//我们还提供了一个免费函数来获取工资,因为它在ADL中很有用
自动获取薪资(人员常量和薪资)->decltype(p.获取薪资())
{
返回p.get_salary();
}
//我们现在不需要成为朋友
//有办法得到薪水。因为有一个免费的功能可用
//在person的名称空间中,我们可以进一步抽象这个函数!
自动薪资负担(人员常量和x、人员常量和y)->decltype(获取薪资(x)+获取薪资(y))
{
返回获取工资(x)+获取工资(y);
}
}
//实际上,在c++17中,我们也可以完全抽象这个概念。。。
模板
自动工资负担(事情和…事情)
{
//在这里,不管名称空间是什么,这个名称空间都是
//搜索名为get|u salary(Thing[&&&| const&&&&]的函数)
回报(拿薪水(东西)+…);
}
名称空间非人类
{
结构机器人{};
//请注意,robot没有get_salary()成员
自动获取工资(robot const&->double{return 5;}
}
int main()
{
自动爱丽丝=人类::人(“爱丽丝”,“程序员”,20000);
自动鲍勃=人类::人(“鲍勃”,“建设者”,10000);
auto robby1=非人类::机器人();
auto robby2=非人类::机器人();
auto robby3=非人类::机器人();
//呼叫薪资负担(人员常量和x、人员常量和y)
std::cout一些您可能会感兴趣的注释:
#include <string>
#include <iostream>
namespace humans
{
class person
{
private:
// certainly never write using namespace::thing in header files.
// if you are going to be using a type, do it in a very confined scope, in a cpp file
std::string fname, lname;
double salary;
public:
person(std::string, std::string, double); // ctor declaration
// you neither need or want a destructor for this class.
// if you define a destructor, you must also define copy & assignment
// operators. See rule of 5, 3 or none.
// define a way to see the salary
double get_salary() const { return salary; }
// there is no such thing as a person plus a person.
// avoid nonsensical mathematical abstractions
// double operator+(person);
};
// let's also provide a free function to get_salary, because it can be useful in ADL
auto get_salary(person const & p) -> decltype(p.get_salary())
{
return p.get_salary();
}
// salary_burden does not need to be a friend now that we
// have a way to get the salary. Since there is a free function available
// in the namespace of person, we could abstract this function a little more!
auto salary_burden(person const& x, person const& y) -> decltype(get_salary(x) + get_salary(y))
{
return get_salary(x) + get_salary(y);
}
}
// indeed in c++17 we could also abstract this concept completely...
template<class...Things>
auto salary_burden(Things&&...things)
{
// here whatever namespace Things is in, this namespace will be
// searched for a function called get_salary(Thing[&&|const&|&])
return (get_salary(things) + ...);
}
namespace non_humans
{
struct robot{};
// note that a robot does not have a get_salary() member
auto get_salary(robot const&) -> double { return 5; }
}
int main()
{
auto alice = humans::person("alice", "the programmer", 20000);
auto bob = humans::person("bob", "the builder", 10000);
auto robby1 = non_humans::robot();
auto robby2 = non_humans::robot();
auto robby3 = non_humans::robot();
// calls salary_burden(person const& x, person const& y)
std::cout << salary_burden(alice, bob) << '\n';
// calls auto salary_burden(Things&&...things)
std::cout << salary_burden(alice, bob, robby1, robby2, robby3) << '\n';
}
#包括
#包括
命名空间人
{
班主任
{
私人:
//当然,永远不要在头文件中使用namespace::thing编写。
//如果要使用类型,请在非常有限的范围内使用cpp文件
std::字符串fname,lname;
双薪;
公众:
person(std::string,std::string,double);//构造函数声明
//这个类既不需要也不需要析构函数。
//如果定义析构函数,还必须定义复制和赋值
//运算符。请参见第5、3或无规则。
//定义查看薪资的方式
double get_salary()常量{return salary;}
//没有一个人加一个人这样的事情。
//避免无意义的数学抽象
//双操作员+(人);
};
//我们还提供了一个免费函数来获取工资,因为它在ADL中很有用
自动获取薪资(人员常量和薪资)->decltype(p.获取薪资())
{
返回p.get_salary();
}
//我们现在不需要成为朋友
//有办法得到薪水。因为有一个免费的功能可用
//在person的名称空间中,我们可以进一步抽象这个函数!
自动薪资负担(人员常量和x、人员常量和y)->decltype(获取薪资(x)+获取薪资(y))
{
返回获取工资(x)+获取工资(y);
}
}
//实际上,在c++17中,我们也可以完全抽象这个概念。。。
模板
自动工资负担(事情和…事情)
{
//在这里,不管名称空间是什么,这个名称空间都是
//搜索名为get|u salary(Thing[&&&| const&&&&]的函数)
回报(拿薪水(东西)+…);
}
名称空间非人类
{
结构机器人{};
//请注意,robot没有get_salary()成员
自动获取工资(robot const&->double{return 5;}
}
int main()
{
自动爱丽丝=人类::人(“爱丽丝”,“程序员”,20000);
自动鲍勃=人类::人(“鲍勃”,“建设者”,10000);
auto robby1=非人类::机器人();
auto robby2=非人类::机器人();
auto robby3=非人类::机器人();
//呼叫薪资负担(人员常量和x、人员常量和y)
std::cout编译器对此怎么说?无论如何,这是运算符重载的滥用,IMHO。这里有几个贡献者。decltype
要求其操作数是完整的类型。更准确地说,因为x+y
涉及函数调用,所以该函数调用不应该包含