How do you declare a template function a friend of a variadic class, both inside and outside the class declaration?
For example, this is how I'd think you'd write it inside the class declaration, but I'm getting an undefined reference error.
#include <tuple>
#include <vector>
namespace ns
{
template<class...>
class Example;
template<class A, class... Bs>
std::vector<A>& get(Example<Bs...>& pExample);
template<class... As>
class Example
{
private:
std::tuple<std::vector<As>...> mVectors;
public:
explicit Example(std::size_t pCapacity)
: mVectors(std::vector<As>(pCapacity)...)
{}
template<class B> //Error: undefined reference to `std::vector<int,std::allocator<int> >& ns::get<int, int, float>(ns::Example<int, float>&)
friend std::vector<B>& get(Example<As...>& pExample)
{
return std::get<std::vector<B>>(pExample.mVectors);
}
};
}
Friend functions do not inherit the template parameter.
#include <tuple>
#include <vector>
namespace ns
{
template<class... As>
class Example;
template<class B, class... As>
std::vector<B>& get(Example<As...>& pExample);
template<class... As>
class Example
{
private:
std::tuple<std::vector<As>...> mVectors;
public:
explicit Example(std::size_t pCapacity)
: mVectors(std::vector<As>(pCapacity)...)
{}
template<class B, class... Cs> // <----
friend std::vector<B>& get(Example<Cs...>& pExample)
{
return std::get<std::vector<B>>(pExample.mVectors);
}
};
}
int main()
{
ns::Example<int,short,char> e(10);
auto v = ns::get<int>(e);
}
Live example
Related
Class B uses a use a template, which is a private member of class A.
I tried friend declaration but the template is still private within the context.
How to allow B to use a private template of A?
Test (also at godbolt.org):
#include <iostream>
#include <vector>
template <class T>
class A {
private:
template<typename R> using V = std::vector<R>;
};
template <typename T, class Prev>
class B {
public:
friend Prev;
typename Prev::template V<T> v_;
};
int main() {
B<int, A<int>> b;
return 0;
}
Compilation Error:
error: ‘template<class R> using V
= std::vector<R, std::allocator<_CharT> >’
is private within this context
typename Prev::template V<T> v_;
^~
Fix (also at godbolt.org)
#include <iostream>
#include <vector>
template <typename T, class Prev> class B;
template <class T>
class A {
template <typename T2, class Prev>
friend class B;
private:
template<typename R> using V = std::vector<R>;
};
template <typename T, class Prev>
class B {
public:
typename Prev::template V<T> v_;
};
int main() {
B<int, A<int>> b;
return 0;
}
I'm writing a templated singleton superclass, that can provide a thread-local instance or a process-global instance. The code below compiles and technically fits my need.
But, how can I write the function implementation outside of the class declaration? How do I declare the function in the class (is the commented line right)?
All similar questions implement the function in the class declaration.
#include <vector>
#include <type_traits>
using namespace std;
template <class t, bool tls=true>
class A{
public:
typedef std::vector<t> Avector;
// static Avector& getVector();
template <class T=t, bool TLS=tls, typename std::enable_if<!TLS>::type* = nullptr>
static Avector&
getVector(){
static Avector v=Avector();
return v;
}
template <class T=t, bool TLS=tls, typename std::enable_if<TLS>::type* = nullptr>
static Avector&
getVector(){
static thread_local Avector v=Avector();
return v;
}
};
int main(){
vector<int>& vi = A<int>::getVector();
vector<double>& vd = A<double, false>::getVector();
return 0;
}
You can instead write
template<typename T, bool>
struct A
{
typedef std::vector<T> Avector;
static Avector& getVector();
};
template<typename T, bool b>
typename A<T, b>::Avector& A<T, b>::getVector()
{
thread_local typename A<T, true>::Avector v;
return v;
}
template<typename T>
class A<T, false>
{
typedef std::vector<T> Avector;
static Avector& getVector();
};
template<typename T>
typename A<T, false>::Avector& A<T, false>::getVector()
{
static typename A<T, false>::Avector v;
return v;
}
Also, generally singletons shouldn't be used
I was searching an answer, and we got one on Stack Overflow 2 years after you posted your question, here : How to use std::enable_if on method of templated class with seperate declaration and definition via specialization.
First, you have to redefine the method as a template, with another typename, and with default value the class's template.
Second, you have to template<> 2 times on the implementation's side.
// hpp
template<typename T>
class A {
template <class U=T, typename std::enable_if_t<myCondition, bool>>
void myMethod();
}
// cpp
template<typename T>
template <class U=T, typename std::enable_if_t<myCondition, bool>>
void A::myMethod() {
// ...
}
If you don't want to define another template parameter, you can define the restriction as return type. Here we changed bool by void, but it can be whatever you want :
// hpp
template<typename T>
class A {
typename std::enable_if_t<myCondition, void>
myMethod();
}
// cpp
template<typename T>
typename std::enable_if_t<myCondition, void>
A::myMethod() {
// ...
}
I have a template class S<T> with a nested template class S<T>::Q<M>. The inner class contains a static instance of itself.
How do I encode the definition of S<T>::Q<M>::q_ in the following code example? (The line marked with <---- error)
#include <iostream>
struct A {};
struct B {};
template<typename T>
struct S {
template<typename M>
struct Q {
int x;
Q() : x(1) {}
static Q q_;
};
};
template<typename T, typename M>
typename S<T>::template Q<M> S<T>::Q<M>::q_; // <---- error
int main()
{
std::cout << S<A>::Q<B>::q_.x;
}
You should define it in the following way:
template<typename T>
template<typename M>
S<T>::Q<M> S<T>::Q<M>::q_ = Q();
Trying to nail down the logic behind explicit specialization of members of class templates I composed this code below:
#include <iostream>
using namespace std;
template<class T> class X
{
public:
template<class U> class Y
{
public:
template<class V> void f(U,V);
void g(U);
};
};
template<> template<> template<class V>
void X<int>::Y<int>::f(int, V) {}
int main() {
X<int>::Y<int> b;
b.f(1, 1);
}
It compiles without any problems. But when i introduce changes shown below, it refuses to compile at all:
#include <iostream>
using namespace std;
template<class T> class X
{
public:
template<class U> class Y
{
public:
template<class V> void f(U,V);
void g(U);
};
};
template<> template<class U> template<class V> // changes
void X<int>::Y<U>::f(U, V) {} // changes
int main() {
X<int>::Y<int> b;
b.f(1, 1);
}
Error:
1>d:\projects\programs\youtube\lesson\lesson\main.cpp(17): error C3860: template argument list following class template name must list parameters in the order used in template parameter list
1>d:\projects\programs\youtube\lesson\lesson\main.cpp(17): error C3855: 'X': template parameter 'T' is incompatible with the declaration
Can somebody explain to me what is going on here? Thank you!
I'm trying to call the class function A<F>::f() from within class S, but I'm getting the following errors when I instantiate an S object ( S<int>s ) and call it's f member function ( s.f() ) :
source.cpp: In instantiation of 'int S<F>::f() [with F = int]':
source.cpp:30:21: required from here
source.cpp:22:25: error: 'A<int>' is not an accessible base of 'S<int>'
Note that this works when I replace return A<F>::f(); inside the declaration of class S with return C<A, F>::f();. But I'm wondering why I can't do it the other way...
#include <iostream>
template <typename T> class A {
public:
int f();
};
template <typename T> int A<T>::f() {
return sizeof(T);
}
template <template <typename> class E, typename D> class C : E<D> {
public:
int f() {
return E<D>::f();
}
};
template <typename F> class S : C<A, F> {
public:
int f() {
return A<F>::f();
}
};
int main() {
S<int>s;
std::cout << s.f();
}
Any help is appreciated and if you require further clarification please feel free to comment.
Update
Since this questions is resolved I guess I should post the code that actually worked:
#include <iostream>
template <typename T> class A {
public:
int f();
};
template <typename T> int A<T>::f() {
return sizeof(T);
}
template <template <typename> class E, typename D> class C : public E<D> {
public:
int f() {
return E<D>::f();
}
};
class S : public C<A, int> {};
int main() {
S s;
std::cout << s.f(); // 4
}
template <typename F> class S : C<A, F>
^
You don't specify a public inheritance, so it defaults to private, making the base classes inaccessible.
I think it is just a matter of using public class inheritance. Try with:
template <template<class> class E, typename D> class C : public E<D> {
public:
int f() {
return E<D>::f();
}
};
template <typename F> class S : public C<A, F> {
public:
int f() {
return A<F>::f();
}
};
When you are trying to call A's version of f() you use the notation A<F>::f(). If A<F> had a static member function f() this function would, indeed, be called. However, A<F> only has a non-static member function f(), i.e., the call gets implicitly translated to this->A<F>::f(). However, S<F> doesn't have a A<F> as an accessible base (it is a private base of C<A, F>). From the looks of it you want to delegate to C<A, F>s version of f():
C<A, F>::f();
which should work because C<A, F> is an accesible base of S<int> or make the E<D> base of C accessible by making it either public or protected.