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

时间:2018-12-29 15:16:04

标签: 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_burden(person x, person y) -> decltype(x+y); // salary burden of two employees
};

ydecltype下方有一个红色的波浪状,Intellisense说cannot convert to incomplete class "person"

这是怎么回事?

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

2 个答案:

答案 0 :(得分:2)

问题在于,即使decltype的操作数可能是不完整的类型,对于用来构成用作decltype的prvalue的prvalue的子表达式也不相同。

decltype(x+y);

等效于

decltype(operator+(x, y));

但是person在其自己的定义中不完整。您可以通过将operator+定义为:

double operator+(person const&);

答案 1 :(得分:1)

您可能会发现有趣的一些笔记:

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