I have a class template
template <class Key, class T, class Hash, template <class> class Allocator>
class Table;
and a function template
template <class Key, class T, class DevHash, template <class> class DevAllocator, class HostHash, template <class> class HostAllocator>
void copyTableToHost(const Table<Key, T, DevHash, DevAllocator> &table, Table<Key, T, HostHash, HostAllocator> &hostTable);
Now I want to grant copyTableToHost()
access to private members of both table
and hostTable
. In order to do that I made a friend declaration in Table
class:
template <class DevHash, template <class> class DevAllocator, class HostHash, template <class> class HostAllocator>
friend void copyTableToHost<Key, T, DevHash, DevAllocator, HostHash, HostAllocator>(const Table<Key, T, DevHash, DevAllocator> &table, Table<Key, T, HostHash, HostAllocator> &hostTable);
My reasoning is that I don't need to specify Key
and T
as template parameters here since these are fixed for a given specialization. At the same time a given specialization needs to be friends with a whole class of functions which differ by the choice of DevHash
, DevAllocator
, HostHash
and HostAllocator
(I am not sure if template template parameters don't mess things up here ...).
The errors I get are of the form member Table<Key, T, Hash, Allocator>::[member name] is inaccessible
which makes me believe that the friend declaration didn't work as intended.
CodePudding user response:
If you want it as a free friend
function template, one option could be to befriend all instances of it:
template <class Key, class T, class Hash, template <class> class Allocator>
class Table {
template <class K, class Ty,
class Hash1, template <class> class Allocator1,
class Hash2, template <class> class Allocator2>
friend void copyTableToHost(const Table<K, Ty, Hash1, Allocator1>& table,
Table<K, Ty, Hash2, Allocator2>& hostTable);
int x = 0; // private
};
template <class Key, class T,
class Hash1, template <class> class Allocator1,
class Hash2, template <class> class Allocator2>
void copyTableToHost(const Table<Key, T, Hash1, Allocator1>& table,
Table<Key, T, Hash2, Allocator2>& hostTable)
{
hostTable.x = table.x; // now ok
}
Another option could be to instead use iterators and populate the table in a member function that takes iterators with the requirement they are dereferenced into a std::pair<Key, T>
- or whatever class template you are using to package each <Key, T>
. It could look like this:
#include <type_traits>
#include <iterator>
template <class Key, class T, class Hash, template <class> class Allocator>
class Table {
public:
template<class It>
requires std::is_same_v<typename std::iterator_traits<It>::value_type,
std::pair<Key, T>>
void copyFrom(It first, It last) {
// copy from `first` to `last`
}
};