How can a class declare all of its variadic template parameters friends? - c++

If I have a class which takes variadic pack of template arguments how can I declare them all to be friends?
Here is what I would like to do in pseudo-code form:
template<typename... Ts>
class AbstractMyClass {
int privateInt;
friend Ts...;
};
class OtherClass;
using MyClass = AbstractMyClass<OtherClass>;
class OtherClass {
public:
void foo(MyClass &c){
c.privateInt = 42;
}
};

This can only be done using "compile time recursion", much like tuples. The gist is (I am on a small laptop right now and by no means able to comfortably type):
template<class .... THINGS> class object;
template<class T> class object {
friend T;
};
template<class T,class ... THINGS>
class object: public object<THINGS> {
friend T;
};
If C++ doesn't like that, try template<> class object<> {}; as the one that ends the recursion (I terminate it with an object in 1 template paramater)
(Thanks to Dietmar Kuhl for formatting)

Related

In C++ can one friend a template class in a non template class for ALL specializations of the template class? [duplicate]

Let's say I'm creating a class for a binary tree, BT, and I have a class which describes an element of the tree, BE, something like
template<class T> class BE {
T *data;
BE *l, *r;
public:
...
template<class U> friend class BT;
};
template<class T> class BT {
BE<T> *root;
public:
...
private:
...
};
This appears to work; however I have questions about what's going on underneath.
I originally tried to declare the friend as
template<class T> friend class BT;
however it appears necessary to use U (or something other than T) here, why is this? Does it imply that any particular BT is friend to any particular BE class?
The IBM page on templates and friends has examples of different type of friend relationships for functions but not classes (and guessing a syntax hasn't converged on the solution yet). I would prefer to understand how to get the specifications correct for the type of friend relationship I wish to define.
template<class T> class BE{
template<class T> friend class BT;
};
Is not allowed because template parameters cannot shadow each other. Nested templates must have different template parameter names.
template<typename T>
struct foo {
template<typename U>
friend class bar;
};
This means that bar is a friend of foo regardless of bar's template arguments. bar<char>, bar<int>, bar<float>, and any other bar would be friends of foo<char>.
template<typename T>
struct foo {
friend class bar<T>;
};
This means that bar is a friend of foo when bar's template argument matches foo's. Only bar<char> would be a friend of foo<char>.
In your case, friend class bar<T>; should be sufficient.
In order to befriend another same-type struct:
#include <iostream>
template<typename T_>
struct Foo
{
// Without this next line source.value_ later would be inaccessible.
template<typename> friend struct Foo;
Foo(T_ value) : value_(value) {}
template <typename AltT>
void display(AltT &&source) const
{
std::cout << "My value is " << value_ << " and my friend's value is " << source.value_ << ".\n";
}
protected:
T_ value_;
};
int main()
{
Foo<int> foo1(5);
Foo<std::string> foo2("banana");
foo1.display(foo2);
return 0;
}
With the output as follows:
My value is 5 and my friend's value is banana.
In template<typename> friend struct Foo; you shouldn't write T after typename/class otherwise it will cause a template param shadowing error.
It's not necessary to name the parameters so you get fewer points of failure if refactoring:
template <typename _KeyT, typename _ValueT> class hash_map_iterator{
template <typename, typename, int> friend class hash_map;
...
The best way to make a template class a friend of a template class is the following:
#include <iostream>
using namespace std;
template<typename T>
class B;
template<typename T>
class A
{
friend class B<T>;
private:
int height;
public:
A()//constructor
A(T val) //overloaded constructor
};
template<typename T>
class B
{
private:
...
public:
B()//constructor
B(T val) //overloaded constructor
};
In my case this solution works correctly:
template <typename T>
class DerivedClass1 : public BaseClass1 {
template<class T> friend class DerivedClass2;
private:
int a;
};
template <typename T>
class DerivedClass2 : public BaseClass1 {
void method() { this->i;}
};
I hope it will be helpful.

Make all derived template classes friend of other class in C++

Let's say I have to following hierarchy:
template<class T> class Base {
protected:
T container;
};
template<class T> class Derived1 : public Base<T> {
public:
void f1() {
/* Does stuff with Base<T>::container */
}
};
template<class T> class Derived2 : public Base<T> {
public:
void f2() {
/* Does stuff with Base<T>::container */
}
};
Now I want an independent Class (not derived from Base) that can access the Base<T>::container directly from Base or any Derived class. I read about template friend classes and it seems to be the solution to my problem but I couldn't figure out the syntax yet.
I am looking for something like:
template<class T> class Foo{
template<T> friend class Base<T>; // <-- this does not work
public:
size_t bar(const Base<T> &b) const{
return b.container.size();
}
};
Derived1<std::vector<int> > d;
d.f1();
Foo<std::vector<int> > foo;
size_t s = foo.bar()
The friend class line causes an error: specialization of ‘template<class T> class Base’ must appear at namespace scope template<T> friend class Base<T> and the member variable container is still not accessible.
A couple of issues:
Just as you don't put a <T> after the class name when defining a class template:
template <class T> class X<T> { ... }; // WRONG
template <class T> class X { ... }; // RIGHT
you shouldn't put it after the class name when declaring a class template, whether in a forward declaration or friend declaration:
template <class T> class X<T>; // WRONG
template <class T> class X; // RIGHT - declares the template exists
template <class T> friend class X<T>; // WRONG
template <class T> friend class X; // RIGHT - says all specializations of X are friends
(Unless you're creating a class template partial specialization. For example, if class template X is already declared, then template <class T> class X<T*> { ... }; defines a partial specialization that will be used instead of the primary template when the template argument is a pointer.)
And you have the friend declaration backwards: it needs to appear inside the class with the non-public member(s), and name the other class(es) which are allowed to use the members. (If it worked the other way around, then any new class could gain access to any other class's private and protected members, without the permission of the owning class!)
So you would need:
template <class T> class Foo;
template<class T> class Base {
template <class U> friend class Foo;
protected:
T container;
};
The forward declaration of Foo is sometimes not needed, but I think it makes things clearer, and it can avoid gotchas when things start getting more complicated with namespaces, nested classes, etc.
Only Base can say Foo is its friend.
template<typename T> friend class Foo; // every Foo<T> is a friend of Base

Advanced C++: Copy configuration (object) in a template template class's instance

I have a problem with templatized classes that I made most abstract with this example.
So for a class which has the form
template <typename T, template <typename T> class MyFunctor>
class MyMainClass
{
MyFunctor<T> myInstance;
public:
setConfigOfMyFunctor<ConfigClass>(const ConfigClass& cfg); //problem is here. How can I write this?
}
I define FunctorClass which I will use as the second template parameter in MyMainClass
template <typename T>
class FunctorClass
{
public:
ConfigClass<T> cfg;
int a;
int b;
int c;
}
where my config class is simply
template <Typename T>
class ConfigClass
{
T cfgval1;
T cfgval2;
public:
void setVals(int cfgVal1, ...);
//.....
}
If I make an object of this class
int main()
{
typedef double T;
MyMainClass<T,FunctorClass> classy;
ConfigClass<T> config;
config.setVals(1, 2, ...);
//so I'm looking for something like the following line (taken from first declaration)
classy.setConfigOfMyFunctor<ConfigClass>(config); //this is supposed to copy the object config to the FunctorClass's object in MyMainClass.
}
So in brief, I want the object config to be copied to MyMainClass<>::FunctorClass<>::cfg
Is that possible?
If you need more information on the problem, please let me know.
Thank you for any efforts.
You needn't parametrize setConfigOfMyFunctor with any type since you already know type of accepted config - ConfigClass<T>.
So you should be able to do it like that:
template <typename T, template <typename T> class MyFunctor>
class MyMainClass
{
MyFunctor<T> myInstance;
public:
template<template <typename T> class Config>
setConfigOfMyFunctor(const Config<T>& cfg) {
myInstance.cfg = cfg;
}
}
(you'll need to add keyword typename somewhere (before Config<T>, most likely) if compiler asks you to)

C++ How to specify all friends of a templated class with a default argument?

To define a friend of a templated class with a default argument, do you need to specify all friends as in the code below (which works)?
// Different class implementations
enum ClassImplType { CIT_CHECK, CIT_FAST, CIT_GPU, CIT_SSE, CIT_NOF_TYPES } ;
// Graph class has default template argument CIT_CHECK
template <typename T, ClassImplType impl_type = CIT_CHECK>
class graph {
//...
};
// Vertex class
template <typename T>
class vertex {
//...
friend class graph<T, CIT_CHECK>;
friend class graph<T, CIT_FAST>;
friend class graph<T, CIT_GPU>;
friend class graph<T, CIT_SSE>;
};
I can imagine that there is a shorter way to denote that the friend is defined for all possible ClassImplType enum values. Something like friend class graph<T, ClassImplType>, but the latter doesn't work of course.
Apologies if the terminology I use is incorrect.
I can imagine that there is a shorter way to denote that the friend is defined for all possible ClassImplType enum values.
Sadly, there really isn't. You might try with
template<ClassImplType I> friend class graph<T, I>;
but the standard simply forbids one to befriend partial specializations:
§14.5.4 [temp.friend] p8
Friend declarations shall not declare partial specializations. [ Example:
template<class T> class A { };
class X {
template<class T> friend class A<T*>; // error
};
—end example ]
You can only either befriend them all:
template<class U, ClassImplType I>
friend class graph;
Or a specific one:
friend class graph<T /*, optional-second-arg*/>;
I can't see how befriending all possible specializations might cause a problem here, to be honest, but let's assume it does. One workaround I know would be using the passkey pattern, though we'll use a slightly cut-down version (we can't use the allow mechanism here, since it doesn't work well for allowing access to all specializations of a template):
template<class T>
class passkey{
passkey(){}
friend T;
// optional
//passkey(passkey const&) = delete;
//passkey(passkey&&) = delete;
};
// Different class implementations
enum ClassImplType { CIT_CHECK, CIT_FAST, CIT_GPU, CIT_SSE, CIT_NOF_TYPES } ;
template<class> struct vertex;
// Graph class has default template argument CIT_CHECK
template <typename T, ClassImplType impl_type = CIT_CHECK>
class graph {
public:
void call_f(vertex<T>& v){ v.f(passkey<graph>()); }
//...
};
// Vertex class
template <typename T>
class vertex {
//...
public:
template<ClassImplType I>
void f(passkey<graph<T,I>>){}
};
Live example with tests.
You'll note that you need to make all functionality that graph needs to access public, but that's not a problem thanks to the passkeys, which can only ever be created by the specified graph specializations.
You can also go farther and create a proxy class which can be used to access the vertex functionality (only graph changes):
// Graph class has default template argument CIT_CHECK
template <typename T, ClassImplType impl_type = CIT_CHECK>
class graph{
typedef passkey<graph> key;
// proxy for succinct multiple operations
struct vertex_access{
vertex_access(vertex<T>& v, key k)
: _v(v), _key(k){}
void f(){ _v.f(_key); }
private:
vertex<T>& _v;
key _key;
};
public:
void call_f(vertex<T>& v){
vertex_access va(v, key());
va.f(); va.f(); va.f();
// or
v.f(key());
}
//...
};
Live example.
You can template the friend statement:
template<typename U, ClassImplType V>
friend class graph_foo;
I'm trying to figure out how to keep the T - I'll update if I find out.
I thought of the following way to 'fix it' by using recursive inheritance.
Inline comments explain what's happening:
#include <type_traits>
#include <string>
#include <iostream>
#include <typeinfo>
// Different class implementations
enum ClassImplType { CIT_CHECK, CIT_FAST, CIT_GPU, CIT_SSE, CIT_NOF_TYPES };
template <typename T, ClassImplType impl_type = CIT_CHECK>
class graph;
// Vertex class
namespace impl
{
template <typename, ClassImplType, typename enabler = void> struct vertex_impl;
///////////////////////////////////////////////////////////////
// actual implementation (stop condition of recursion)
static const ClassImplType CIT_ENDMARKER = (ClassImplType) -1;
template <typename T> struct vertex_impl<T, CIT_ENDMARKER>
{
protected: // make it protected rather than private
int secret() const { return 42; }
};
///////////////////////////////////////////////////////////////
// recursion, just to mark friends
template <typename T, ClassImplType impl_type>
struct vertex_impl<T, impl_type, typename std::enable_if<CIT_ENDMARKER != impl_type>::type>
: public vertex_impl<T, ClassImplType(impl_type - 1)>
{
friend class ::graph<T, impl_type>;
};
}
///////////////////////////////////////////////////////////////
// Public typedef
#if 1
template <typename T> struct vertex : impl::vertex_impl<T, CIT_NOF_TYPES> { };
#else // or c++11
template <typename T> using vertex = impl::vertex_impl<T, CIT_NOF_TYPES>;
#endif
template <typename T, ClassImplType impl_type>
class graph
{
public:
static void TestFriendOf(const vertex<T>& byref)
{
std::cout << byref.secret() << std::endl;
}
};
int main(int argc, const char *argv[])
{
vertex<int> t;
graph<int, CIT_CHECK> :: TestFriendOf(t);
graph<int, CIT_FAST> :: TestFriendOf(t);
graph<int, CIT_GPU> :: TestFriendOf(t);
graph<int, CIT_SSE> :: TestFriendOf(t);
graph<int, CIT_NOF_TYPES> :: TestFriendOf(t);
}
This works on gcc and clang.
See it live on http://liveworkspace.org/code/f03c0e25a566a4ca44500f4aaecdd354
PS. This doesn't exactly solve any verbosity issues at first sight, but you could make the solution more generic, and inherit from a different 'base-case' instead of the hard-coded one, in which case the boileplate could potentially be compensated for (in case you have many classes that need to befriend families of graph types)
Class cannot become friend of partial specialization according to this "non-bug" explanation: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=5094
What clenches it is that 14.5.3, p9
explicitly prohibits friend declarations of partial specializations:
-9- Friend declarations shall not declare partial specializations.
[Example:
template<class T> class A { };
class X {
template<class T> friend class A<T*>; // error
};
容nd example]
But I come to the solution, which does not look perfect, neither it is easy to use. The idea is to create intermediate friend inner class, just to forward "friendship" to outer class. The disadvantage (or advantage?) is that one has to wrap all function/member variables which shall be available to outer friend:
// Different class implementations
enum ClassImplType { CIT_CHECK, CIT_FAST, CIT_GPU, CIT_SSE, CIT_NOF_TYPES } ;
template <typename T>
class vertex;
// Graph class has default template argument CIT_CHECK
template <typename T, ClassImplType impl_type = CIT_CHECK>
class graph {
typedef typename vertex<T>::template graph_friend<impl_type> graph_friend;
public:
graph(vertex<T>& a) { graph_friend::foo(a); } // here call private method
//...
};
// Vertex class
template <typename T>
class vertex {
//...
int foo() {}
public:
template <ClassImplType impl_type>
class graph_friend {
static int foo(vertex& v) { return v.foo(); }
friend class graph<T,impl_type>;
};
};
int main() {
vertex<int> a;
graph<int,CIT_SSE> b(a);
}

Class template with template class friend, what's really going on here?

Let's say I'm creating a class for a binary tree, BT, and I have a class which describes an element of the tree, BE, something like
template<class T> class BE {
T *data;
BE *l, *r;
public:
...
template<class U> friend class BT;
};
template<class T> class BT {
BE<T> *root;
public:
...
private:
...
};
This appears to work; however I have questions about what's going on underneath.
I originally tried to declare the friend as
template<class T> friend class BT;
however it appears necessary to use U (or something other than T) here, why is this? Does it imply that any particular BT is friend to any particular BE class?
The IBM page on templates and friends has examples of different type of friend relationships for functions but not classes (and guessing a syntax hasn't converged on the solution yet). I would prefer to understand how to get the specifications correct for the type of friend relationship I wish to define.
template<class T> class BE{
template<class T> friend class BT;
};
Is not allowed because template parameters cannot shadow each other. Nested templates must have different template parameter names.
template<typename T>
struct foo {
template<typename U>
friend class bar;
};
This means that bar is a friend of foo regardless of bar's template arguments. bar<char>, bar<int>, bar<float>, and any other bar would be friends of foo<char>.
template<typename T>
struct foo {
friend class bar<T>;
};
This means that bar is a friend of foo when bar's template argument matches foo's. Only bar<char> would be a friend of foo<char>.
In your case, friend class bar<T>; should be sufficient.
In order to befriend another same-type struct:
#include <iostream>
template<typename T_>
struct Foo
{
// Without this next line source.value_ later would be inaccessible.
template<typename> friend struct Foo;
Foo(T_ value) : value_(value) {}
template <typename AltT>
void display(AltT &&source) const
{
std::cout << "My value is " << value_ << " and my friend's value is " << source.value_ << ".\n";
}
protected:
T_ value_;
};
int main()
{
Foo<int> foo1(5);
Foo<std::string> foo2("banana");
foo1.display(foo2);
return 0;
}
With the output as follows:
My value is 5 and my friend's value is banana.
In template<typename> friend struct Foo; you shouldn't write T after typename/class otherwise it will cause a template param shadowing error.
It's not necessary to name the parameters so you get fewer points of failure if refactoring:
template <typename _KeyT, typename _ValueT> class hash_map_iterator{
template <typename, typename, int> friend class hash_map;
...
The best way to make a template class a friend of a template class is the following:
#include <iostream>
using namespace std;
template<typename T>
class B;
template<typename T>
class A
{
friend class B<T>;
private:
int height;
public:
A()//constructor
A(T val) //overloaded constructor
};
template<typename T>
class B
{
private:
...
public:
B()//constructor
B(T val) //overloaded constructor
};
In my case this solution works correctly:
template <typename T>
class DerivedClass1 : public BaseClass1 {
template<class T> friend class DerivedClass2;
private:
int a;
};
template <typename T>
class DerivedClass2 : public BaseClass1 {
void method() { this->i;}
};
I hope it will be helpful.