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;
}
Related
I have a class
template<typename T, typename U>
class A {
T i;
}
And i have a class B that should use the same types as class A
template<typename A_Type>
class B
: public A_Type
{
T j; // here I need a class member of the same type as the first type of A_Type (T from class A)
}
So I would need something like
template<typename A_Type<T, U>>
class B
: public A_Type
{
T j;
}
This notation is obviously not working but is there a notation that would fit my needs?
You can provide a member alias in A :
template<typename T, typename U>
class A {
T i;
using value_type = T;
};
template<typename A_Type>
class B
: public A_Type
{
typename A_Type::value_type;
};
Or use specialization to deduce the type of the argument:
template<typename T, typename U>
class A {
T i;
using value_type = T;
};
template<typename A_Type>
class B : public A_Type {};
template <typename T,typename U>
class B<A<T,U>> : A<T,U> {
T j;
};
As mentioned in comments, try to be careful with terminology. Using the terms right avoids issues. Neither A nor B are classes. They are class templates. And the member alias should be protected (or placed in a seperate trait template <typename A> struct get_T_from_instantiation_of_A;)
Can't you just pass that type ?
template<typename A_Type, typename T>
class B
: public A_Type
{
T j; // here I need a class member of the same type as the first type of A_Type (T from class A)
}
You could create some type traits to help out.
First one to test if a type is really an A type:
#include <type_traits>
template<class T>
struct is_A_type {
static std::false_type test(...);
template<template<class...> class U, class... V,
std::enable_if_t<std::is_same_v<U<V...>, A<V...>>, int> = 0>
static std::true_type test(const U<V...>&);
static constexpr bool value = decltype(test(std::declval<T>()))::value;
};
template<class T>
inline constexpr bool is_A_type_v = is_A_type<T>::value;
Then a trait to get the type of the first template parameter:
template<class T>
struct first_type {
static void test(...);
template<template<class...> class U, class F, class... V>
static auto test(const U<F, V...>&) -> F;
using type = decltype(test(std::declval<T>()));
};
template<class T>
using first_type_t = typename first_type<T>::type;
These traits could then be used like so:
template<class A_Type>
class B : public A_Type {
static_assert(is_A_type_v<A_Type>, "A_Type must be an A type");
using T = first_type_t<A_Type>;
T j;
};
Considering the following couple of classes:
template <typename T1, typename T2>
class A{
public:
// ...
};
template<typename _T>
struct alias { typedef A<int,_T> intA; };
class B{
public:
// ...
template <typename _T> B& operator=(const typename alias<_T>::intA& _arg) { };
};
When I try to assign an object of class A<int,int> to an object of class B, I get the following compilation error:
template argument deduction/substitution failed: couldn't deduce template parameter ‘_T’
Is there an alternative way to use something of a typedef as the input argument to B::operator=()??
templated using might fix the issue
template <typename T1, typename T2>
class A{
public:
// ...
};
template<typename _T>
using alias = A<int,_T>;
class B{
public:
// ...
template <typename _T> B& operator=(const alias<_T>& ) { return *this; };
};
void f()
{
B b;
A<int, int> a;
b = a;
}
The problem is that intA is a dependant name. Templates cannot be deduced from dependant names. See for example: Dependent Types: Template argument deduction failed.
You are also missing the typename keyword.
You can either explicitly specify the type for the operator:
template <typename T1, typename T2>
struct A{ };
template<typename _T>
struct alias { typedef A<int,_T> intA; };
struct B
{
template <typename T> B& operator=(const typename alias<T>::intA& _arg) { };
};
int main()
{
A<int,int> a;
B b;
b.operator=<int>(a);
return 0;
}
or you can have a specific, non-dependant-name parameter using a templated alias (with or without a function):
template <typename T1, typename T2>
struct A{ };
template<class T>
using alias_int = A<int, T>;
struct alias
{
template<class T>
using intA = A<int, T>;
};
struct B
{
template <typename T> B& operator=(const alias_int<T>& _arg) { };
};
struct C
{
template <typename T> C& operator=(const alias::intA<T>& _arg) { };
};
int main()
{
A<int,int> a;
B b;
C c;
b = a;
c = a;
return 0;
}
I'm getting a different error (using g++ 5.4):
need ‘typename’ before ‘alias<_T>::intA’ because ‘alias<_T>’ is a dependent scope
and true enough the following compiles for me:
template <typename T1, typename T2>
class A{
public:
// ...
};
template<typename _T>
struct alias { typedef A<int,_T> intA; };
class B{
public:
// ...
template <typename _T> B& operator=(const typename alias<_T>::intA& _arg) { };
};
I think the reason is that alias<_T>::intA isn't an actual type but a templated typename.
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
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();
Can we specialize a template class for a templated class?
template<>
class Storage8<MyClass<T>>
{
—
—
};
Here MyClass is a templated class. Is the above valied? Where do we have to mention
template for MyClass?
This should work:
// class templae for Storage8. It can just be a forward declaration
template <typename T> class Storage8;
// or a default defintion.
template <typename T> class Storage8
{
};
// Class templae for MyClass
template <typename T>
class MyClass
{
};
// Specialization of Storage8 for MyClass<T>
template <typename T>
class Storage8<MyClass<T>>
{
};
You totally can. Example:
#include <vector>
using std::vector;
template<typename T>
struct X {
static const int A = 0;
};
template<typename U>
struct X<vector<U> > {
static const int A = 1;
};
int main() {
static_assert(X<vector<int> >::A == 1, "fail");
return 0;
}