我正在尝试构建一个program,我从互联网上下载了它的源代码。当我尝试编译它时,出现错误信息

friend declaration specifying a default argument must be the only declaration

这是有问题的代码:
typedef int Var;
struct Lit {
    int     x;
    // Use this as a constructor:
    friend Lit mkLit(Var var, bool sign = false);
    bool operator == (Lit p) const { return x == p.x; }
    bool operator != (Lit p) const { return x != p.x; }
    bool operator <  (Lit p) const { return x < p.x;  }
inline  Lit  mkLit(Var var, bool sign) { Lit p; p.x = var + var + (int)sign; return p; }

我发现了几个可以解决此问题的问题,但问题相当深刻,我不太理解这些解释。 answer to this question表示我可以通过以下操作来解决问题:将mkLit的内联定义移到结构之前,从好友函数声明中删除默认参数,然后将其移至内联定义。它是否正确?

但更简单地说,我不明白为什么结构需要 friend 功能,因为它的成员无论如何都是公共(public)的。接受的this question答案给出了一个基于参数的查找的答案(我的无知使我无法理解),但是我看不到它在这种情况下适用。

仅删除好友函数声明并将默认参数移至内联函数定义是否有任何缺点?如果是这样,您能举一个简单的例子吗?

最佳答案

我花了一段时间才知道,但最终我发现了。

因此,我忽略了误导性的标题(已经足够answered byuser463035818 IMHO了),并专注于



引起了我的注意。

因此,我不再重复关于friend和访问公共(public)成员的说法,因为我认为此错误涉及另一个问题。

首先,我在coliru上尝试了OP的示例(有一点点修复和一个main()进行测试):

#include <iostream>

typedef int Var;
struct Lit {
    int     x;
    // Use this as a constructor:
    friend Lit mkLit(Var var, bool sign = false);
    bool operator == (Lit p) const { return x == p.x; }
    bool operator != (Lit p) const { return x != p.x; }
    bool operator <  (Lit p) const { return x < p.x;  }
};
inline  Lit  mkLit(Var var, bool sign) { Lit p; p.x = var + var + (int)sign; return p; }

int main()
{
  Lit lit2 = mkLit(123, false);
  std::cout << "lit2.x: " << lit2.x << '\n';
  return 0;
}

输出:

g++ (GCC) 8.1.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

lit2.x: 246

Live Demo on coliru

嗯是的运行良好。

然后我这次用clang HEAD 8.0.0在wandbox上做了同样的事情:

Start

prog.cc:7:16: error: friend declaration specifying a default argument must be a definition
    friend Lit mkLit(Var var, bool sign = false);
               ^
prog.cc:12:14: error: friend declaration specifying a default argument must be the only declaration
inline  Lit  mkLit(Var var, bool sign) { Lit p; p.x = var + var + (int)sign; return p; }
             ^
prog.cc:7:16: note: previous declaration is here
    friend Lit mkLit(Var var, bool sign = false);
               ^
2 errors generated.

1

Finish

Live Demo on wandbox

我们到了。

因此,我试图了解clang抱怨什么。

最后,我发现clang可以找到Lit Lit::mkLit(),但与以后定义的Lit mkLit()不匹配。

这可以通过在mkLit()之前插入的struct Lit原型(prototype)来解决:
typedef int Var;

Lit mkLit(Var var, bool sign = false);

struct Lit {
    int     x;
    // Use this as a constructor:
    friend Lit mkLit(Var var, bool sign);
    bool operator == (Lit p) const { return x == p.x; }
    bool operator != (Lit p) const { return x != p.x; }
    bool operator <  (Lit p) const { return x < p.x;  }
};

现在,我遇到了一个新问题:为Lit定义原型(prototype)时,尚未知道mkLit()
因此,我需要对Lit进行前向声明并最终得到:
#include <iostream>

typedef int Var;

struct Lit;
Lit mkLit(Var var, bool sign = false);

struct Lit {
    int     x;
    // Use this as a constructor:
    friend Lit mkLit(Var var, bool sign);
    bool operator == (Lit p) const { return x == p.x; }
    bool operator != (Lit p) const { return x != p.x; }
    bool operator <  (Lit p) const { return x < p.x;  }
};
inline  Lit  mkLit(Var var, bool sign) { Lit p; p.x = var + var + (int)sign; return p; }

int main()
{
  Lit lit2 = mkLit(123, false);
  std::cout << "lit2.x: " << lit2.x << '\n';
  return 0;
}

输出:

Start

lit2.x: 246

0

Finish

Live Demo on wandbox

问题已解决。

我必须承认,我不确定g++是否接受原始版本(虽然不应该接受)或clang是否拒绝原始版本(尽管不应该)。我的肚子感觉倾向于前者(即clang是正确的)...

在再次考虑g++中会发生什么之后,我得出的结论是它可以执行以下操作:
  • 接受friend Lit Lit::mkLit()(从未使用过)
  • 定义另一个Lit mkLit()

  • 为了找出我将“struct Lit”“转换”为class Lit,这也给g++带来了错误:
    #include <iostream>
    
    typedef int Var;
    class Lit {
        int     x;
        // Use this as a constructor:
        friend Lit mkLit(Var var, bool sign = false);
        bool operator == (Lit p) const { return x == p.x; }
        bool operator != (Lit p) const { return x != p.x; }
        bool operator <  (Lit p) const { return x < p.x;  }
    };
    inline  Lit  mkLit(Var var, bool sign) { Lit p; p.x = var + var + (int)sign; return p; }
    
    int main()
    {
      Lit lit2 = mkLit(123, false);
      std::cout << "lit2.x: " << lit2.x << '\n';
      return 0;
    }
    

    输出:

    g++ (GCC) 8.1.0
    Copyright (C) 2018 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    
    main.cpp: In function 'int main()':
    main.cpp:17:35: error: 'int Lit::x' is private within this context
       std::cout << "lit2.x: " << lit2.x << '\n';
    

    Live Demo on coliru

    因此,OP的原始版本仅适用于g++,因为带有公共(public)struct Litint Lit::x根本不需要friend Lit::mkLit()

    现在,我有点困惑。哪个是正确的g++clang?我不知道。

    关于c++ - 为什么结构需要 friend 功能?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52369155/

    10-10 17:29