I want to declare a friend class only if some (compile-time) condition is true. For example:
// pseudo-C++
class Foo {
if(some_compile_time_condition) {
friend class Bar;
}
};
I did not find any solution on the internet. I went through all the answers to the question Generating Structures dynamically at compile time. Many of them use the C++11 std::conditional, but I would like to know if it is possible to do this in C++03 without using the preprocessor.
This solution https://stackoverflow.com/a/11376710/252576 will not work because friendship is not inherited ( friend class with inheritance ).
Edit Just to make this more easily visible, as mentioned below in the comment: This requirement is unusual. This is part of a new research project in hardware simulation, that I am working on. The testbench is written in C++, and I want to display the variables in a waveform. I have researched various other options, and figured out that I need to use a friend class, due to practical considerations. The friend will capture the values and generate the waveform, but I would prefer to have the friend only when the waveform is required, and not all the time.
Use friend std::conditional<C, friendclass, void>::type; where C is your condition. A nonclass type friend will be ignored.
The conditional template is easily implemented in C++03. However since C++03 does not support typedef friends you need to use the following syntax there
namespace detail { class friendclass {}; }
class Foo {
friend class std::conditional<C,
friendclass, detail::friendclass>::type::friendclass;
};
Note that the detail dummy class name needs to match the name of the potential friend in this workaround.
[class.friend]/3 tells this :
A friend declaration that does not declare a function shall have one of the following forms:
friend elaborated-type-specifier ;
friend simple-type-specifier ;
friend typename-specifier ;
therefore it is not possible to conditionally declare friends of a class, without a macro.
It seems, unfortunately, not possible within the C++ compiler: ie, it seems that only the preprocessor may help here. Note: Johannes has a proposal, so there is hope!
However I would note that:
friendship does not require you to actually use it
friendship is a pure compile-time construct (like access specifiers) and does not incur any runtime penalty on any major compiler
there is no reason not to have unconditional friendship, but only use it if some conditions (static or dynamic) are met.
Note: in the future, this is something that the static_if proposal could cover.
Note: Johannes has pretty much nailed it. In '03 you cannot befriend
a typedef - but if you know you have a class, then you can refer to
it's injected class name.
Johannes' answer also has the benefit of using standard library functionality which too is always a good thing.
#define some_compile_time_condition 0
class Foo;
template <int Condition> class TestCondition {
private:
friend class Foo;
struct Type {
struct Bar;
};
};
template <> class TestCondition<1> {
public:
typedef Bar Type;
};
struct Bar
{
public:
void foo (Foo &);
};
class Foo {
private:
friend struct TestCondition< some_compile_time_condition >::Type::Bar;
int m_i;
};
void Bar::foo (Foo & foo)
{
foo.m_i = 0;
}
It's still different to the requirement in that Foo always has a
friend, but the befriended class changes based on the value of the
option.
An interesting side question is whether it is an ODR violation to have
versions of Foo both with and without some_compile_time_condition
set to 1.
I think you take 1 preprocessor and write your source code inside that.
bool flag = false;
#ifdef _MY_FRIEND_
friend class sample
flag = true;
#endif
if (flag)
{
...
...
...
}
class Foo {
#ifdef _MY_FRIEND_
friend class Bar;
#endif
}
};
Here _MY_FRIEND_ is a preprocessor and if you add that preprocessor then at compile time your class Bar will be the friend class...you can use that preprocssor any where when you want to need class Bar as a friend class.other wise compile without the preprocessor then it wont allow u to add Bar as a friend class of Foo
Please correct me if i understood the question wrong.
Related
I wish to declare multiple C++ friend classes in one statement as below, just to tidy the code. The reason is, in my actual application, there will be three or four friend classes, so it'll be messier than this sample.
Is it possible in any way?
class A{
friend class B, C; // this doesn't work
// friend class B;
// friend class C; // these two would be okay
};
class B{};
class C{};
No you need to write it out longhand.
I can't think of a grammatical reason why your notation couldn't be introduced. (C++17 allows you to shorten the namespace notation, for example, so you're idea is not without precedent).
Why don't you propose your idea to the C++ standards committee?
Of course there will be counter-arguments centred around compiler complexity.
Whole classes - you can't, as friend declaration in that case also acts like forward declaration and that would be conflicting syntax.
But you can declare members of various classes as friends in one statement, if those are already complete:
#include "class_b.h"
#include "class_c.h"
class A {
friend B::B(), C::~C();
};
I understand that the following C++ code snippet should produce an error in the definition of g, because p.t.x is private and cannot be accessed there.
class P {
class T {
int x;
friend class P;
};
T t;
friend void g(P &p);
};
void g(P &p) { p.t.x = 42; }
What puzzles me is the next snippet. It differs only in the fact that the definition of the friend function g now occurs inside class P.
class P {
class T {
int x;
friend class P;
};
T t;
friend void g(P &p) { p.t.x = 42; }
};
Clang++ (both 6.0.0-1ubuntu2 and Apple version clang-1100.0.33.8) compiles the latter with no error, whereas GNU C++ (7.5.0-3ubuntu1~18.04) produces the same error as in the former snippet.
I understand that the function g defined in the latter case is not in the same scope
as the one defined in the former (cf. a related question and an older longer discussion) and it's only visible through ADL. But I think what I'm asking here is different: should the declaration friend class P in class T extend to the body of friend function g or not?
The relevant part of the C++ standard (§11.3 or §11.9.3 in more recent drafts) states that:
7 ... A friend function defined in a class is in the (lexical) scope
of the class in which it is defined. A friend function defined outside
the class is not (6.5.1).
So I understand that Clang++ and GNU C++ interpret differently what is meant by "lexical scope" (see also this answer to the previous related question). Clang++ seems to compile g as if it were a friend of class T, probably because it's in the lexical scope of class P which is a friend of class T, whereas GNU C++ does not.
Is there a bug in one of the two compilers?
If yes, which one?
Regardless of the answers to the previous questions, isn't this something that the standard should formalise better?
This looks like CWG1699 (which is still open).
1699. Does befriending a class befriend its friends?
According to 14.3 [class.friend] paragraph 2,
Declaring a class to be a friend implies that the names of private and protected members from the class granting friendship can be accessed in the base-specifiers and member declarations of the befriended class.
A friend declaration is a member-declaration, but it is not clear how far the granting of friendship goes in a friend declaration. For example:
class c {
class n {};
friend struct s;
};
struct s {
// #1 and #2 are not relevant for this question
friend void f() { c::n(); } // #3
};
In particular, if a friend function is defined inside the class definition, as in #3, does its definition have access to the private and protected members of the befriending class? Implementations vary on this point.
For starters - disclaimer: this is my interpretation of the standard and even though I think it's the right one, one can't be sure what was really meant.
tl;dr
Yes.
IMO clang++
If you look below you will notice it is formalised pretty good.
Full answer
Having said that I think there are two relevant quotes from the standard. First is this:
11.9 Member access control
1 A member of a class can be
(1.1) - private; that is, its name can be used only by members and friends of the class in which it is declared.
and the second is:
11.9.3 Friends [class.friend]
1 A friend of a class is a function or class that is given permission to use the private and protected member names from the class.
A class specifies its friends, if any, by way of friend declarations.
Such declarations give special access rights to the friends, but they do not make the nominated friends members of the befriending class.
From these two one can deduce a few things. But the most important one is that even inline friend cannot access private members of class defined inside befriended class. Why? Because it is neither member nor friend of the nested class. And from that it seems the g++ is right here.
Does anyone know why typedefs of class names don't work like class names for the friend declaration?
class A
{
public:
};
class B : public A
{
public:
typedef A SUPERCLASS;
};
typedef A X;
class C
{
public:
friend class A; // OK
friend class X; // fails
friend class B::SUPERCLASS; // fails
};
It can't, currently. I don't know the reason yet (just looking it up, because i find it interesting). Update: you can find the reason in the first proposal to support typedef-names as friends: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1520.pdf . The reason is that the Standard only supported elaborated-type-specifiers. It's easy to allow only those, and say if the entity declared as friend is not declared yet, it will be made a member of the surrounding namespace. But this means that if you want to use a template parameter, you would have to do (a class is required then for example)
friend class T;
But that brought additional problems, and it was figured not worth the gain. Now, the paper proposes to allow additional type specifiers to be given (so that this then allows use of template parameters and typedef-names).
The next C++ version (due to 2010) will be able to do it.
See this updated proposal to the standard: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1791.pdf . It will not allow only typedef names, but also template parameters to be used as the type declared as friend.
AFAIK, In C++ typedef does not create a full-fledged synonyms when used in conjuction with classes. In other words, it's not like a macro.
Among the restrictions is that the synonym cannot appear after a class or struct prefix, or be used as a destructor or constructor name. You also cannot subclass the synonym. I would bet that is also means you can't friend it.
I tried in the VC++ 8.0 the code:
...
class C
{
public:
friend class A;
friend X;
friend B::SUPERCLASS;
};
...
It is compiled without errors.
I am not aware whether it MS specific or not.
A typedef defines a type. Friend decls declare friend classes or functions (substantially scopes), which then have "access" to the non public area of the declaring class...
Primitives, i.E. a float or an int* don't define a scope with code etc.,
they don't "use" the class anyway.
Don't forget, you can also "pack" call conventions, alignment attribs and other compiler specific stuff in a typedef, i.e. multiple vector TYPES implemented by the same class but with distinct alignment attribs. => A type is not a class, but vice versa.
IMHO, declaring a friend typedef can be useful, but when "class typedefs" from anywhere can be set as friend, the friendships can become extremely incomprehensible and therefore error-prone, especially where templates are used excessively.
Invalidating a single typedef can mess up the whole project due to widespread dependencies.
Template friends and the 0x template typedefs are useful, but don't relax the rules of a friend declaration.
I don't know of any proposal concerning friend typedefs.
I never really had a necessity for a global variable in a template (and actually I don't support a design like this very much) but this topic got me curious.
Even though answered, it inspired me trying a different approach. Instead of using inheritance, I came up with this:
class Bar {};
class {
private:
Bar bar;
template <class T> friend class Foo;
} static foobar_singleton;
template <class T>
class Foo
{
public:
static Bar bar() { return foobar_singleton.bar; }
};
To me, the foobar_singleton works similarly to a 'non-member static private', since its content will be only acessible by the template class Foo. It also avoids inheritance though I am not sure this is an advantadge actually. My solution seems possible to be contained header-only, without necessity about another definition file.
I would like to see what are the opinions about this approach compared to the one utilized as an answer for the thread that got me curious. For instance, some examples of questions I'd like to hear about:
1. Do you see any clear advantadge in my example? Or for that matter, clear disavantadge?
2. Would you advice making bar attribute a static member and naming the class used as singleton?
3. This reminds any of you of any design pattern? Similar to pimpl idiom maybe?
4. You see any compiler portability problems? (I've tested it only with MSVC and GCC)
5. I'm right about being a possible header-only implementation? I'm actually not completely sure about the static variable foobar_singleton
Thanks in advance!
The static variable foobar_singleton in your example will be a different variable in every translation unit (internal linkage!). Which is a kind-of a show stopper.
The inheritance in the original topic is only used to "inject" the common static variable into the namespace of the template. If that's not a requirement, just don't derive Foo from FooBase, works just as well.
If it's needed for whatever reason, I would derive privately, which should eliminate any possible side effects one could encounter from introducing an additional base-class. And of course add the helper-class as the last base-class, if Foo inherits other classes too.
If you want a header-only solution:
typedef int Bar;
template <class DummyType>
class FooCommonStatics
{
static Bar s_bar;
template <class T>
friend class Foo;
};
template <class DummyType>
Bar FooCommonStatics<DummyType>::s_bar;
template <class T>
class Foo
{
public:
// void is just a dummy-type, any type that's not dependent on T would do
typedef FooCommonStatics<void> CommonStatics;
Foo()
{
CommonStatics::s_bar++;
}
private:
T m_something;
};
Does anyone know why typedefs of class names don't work like class names for the friend declaration?
class A
{
public:
};
class B : public A
{
public:
typedef A SUPERCLASS;
};
typedef A X;
class C
{
public:
friend class A; // OK
friend class X; // fails
friend class B::SUPERCLASS; // fails
};
It can't, currently. I don't know the reason yet (just looking it up, because i find it interesting). Update: you can find the reason in the first proposal to support typedef-names as friends: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1520.pdf . The reason is that the Standard only supported elaborated-type-specifiers. It's easy to allow only those, and say if the entity declared as friend is not declared yet, it will be made a member of the surrounding namespace. But this means that if you want to use a template parameter, you would have to do (a class is required then for example)
friend class T;
But that brought additional problems, and it was figured not worth the gain. Now, the paper proposes to allow additional type specifiers to be given (so that this then allows use of template parameters and typedef-names).
The next C++ version (due to 2010) will be able to do it.
See this updated proposal to the standard: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1791.pdf . It will not allow only typedef names, but also template parameters to be used as the type declared as friend.
AFAIK, In C++ typedef does not create a full-fledged synonyms when used in conjuction with classes. In other words, it's not like a macro.
Among the restrictions is that the synonym cannot appear after a class or struct prefix, or be used as a destructor or constructor name. You also cannot subclass the synonym. I would bet that is also means you can't friend it.
I tried in the VC++ 8.0 the code:
...
class C
{
public:
friend class A;
friend X;
friend B::SUPERCLASS;
};
...
It is compiled without errors.
I am not aware whether it MS specific or not.
A typedef defines a type. Friend decls declare friend classes or functions (substantially scopes), which then have "access" to the non public area of the declaring class...
Primitives, i.E. a float or an int* don't define a scope with code etc.,
they don't "use" the class anyway.
Don't forget, you can also "pack" call conventions, alignment attribs and other compiler specific stuff in a typedef, i.e. multiple vector TYPES implemented by the same class but with distinct alignment attribs. => A type is not a class, but vice versa.
IMHO, declaring a friend typedef can be useful, but when "class typedefs" from anywhere can be set as friend, the friendships can become extremely incomprehensible and therefore error-prone, especially where templates are used excessively.
Invalidating a single typedef can mess up the whole project due to widespread dependencies.
Template friends and the 0x template typedefs are useful, but don't relax the rules of a friend declaration.
I don't know of any proposal concerning friend typedefs.