I\'m trying to build a program whose source I downloaded from the internet. When I try to compile it, I get the error message
friend declaration specifying
It took a while until I got it but finally I found out.
Thereby, I ignore the mis-leading title (which has already been answered by user463035818 IMHO sufficiently) and concentrate on
friend declaration specifying a default argument must be the only declaration
which raised my attention.
Therefore, I don't repeat what has been said about friend
and access to public members because I think this error deals with a different issue.
First I tried example of OP on coliru (with a little fix and a main()
to test):
#include
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;
}
Output:
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
Ah, yepp. Runs fine.
Then I did the same on wandbox this time with clang HEAD 8.0.0
:
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
Here we are.
So, I tried to understand what clang
complains about.
Finally, I found that clang
finds Lit Lit::mkLit()
and this does not match Lit mkLit()
defined later.
This can be fixed by a prototype for mkLit()
inserted before struct Lit
:
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; }
};
Now, I get a new issue: Lit
not (yet) known when proto defined for mkLit()
.
So, I need a forward declaration for Lit
and end up with:
#include
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;
}
Output:
Start
lit2.x: 246
0
Finish
Live Demo on wandbox
Problem fixed.
I must admit that I'm not sure whether g++
accepts the original version although it shouldn't or whether clang
denies the original version although it shouldn't. My stomache feeling tends to the former (i.e. clang
is correct)...
After thinking again what happens in g++
, I came to the conclusion that it does the following:
accept the friend Lit Lit::mkLit()
(which is never used)
defining another Lit mkLit()
.
To find out I "converted" struct Lit
to class Lit
and this brings an error in g++
as well:
#include
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;
}
Output:
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
So, the original version of OP just worked in g++
because struct Lit
with public int Lit::x
simply doesn't need the friend Lit::mkLit()
.
Now, I'm a bit puzzled. Which one is right g++
or clang
? I don't know.