接受类参数的友元函数的尾随返回类型

Trailing return type for a friend function that accepts class arguments

本文关键字:返回类型 函数 友元 参数      更新时间:2023-10-16

对于下面的代码:

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
};

我在decltype里面y下面有一个红色的波浪线,智能感知说cannot convert to incomplete class "person"

这到底是怎么回事?

注意:包括 ctor 和 dtor 在内的方法的定义在不同的翻译单元中。我想这不是这里错误的原因。

问题是因为即使decltype的操作数可能是不完整的类型,用于形成充当操作数的 prvalue 的子表达式也是如此decltype

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';
}