I have five classes, declared so:
template <typename T>
class A {
void fn(X);
};
template <typename T>
class B {};
class C {};
class D {};
class X {};
and I have two instances declared so:
A<B<C>> abc;
A<B<D>> abd;
How can I templatize fn so that one must call abc.fn() with an object of type C and abd.fn() with an object of type D?
You can do a partial specialization of your class like this:
template <typename T> class A;
template <typename T> class B {};
template <typename T>
class A<B<T> > {
public:
void fn(T) { }
};
class C {};
class D {};
int main(int,char**)
{
A<B<C>> abc;
A<B<D>> abd;
abc.fn(C());
abd.fn(D());
return 0;
}
If you want it to work for any template, and not just B, you can partially specialize class A like this:
template <typename T,template <typename> class U>
class A<U<T> > {
public:
void fn(T) { }
};
This is not going to be too pretty.
template <typename T>
class B {public: typedef T type;};
template <typename T>
class A {
void fn(typename T::type X);
//void fn(...){} // would prevent an error if T does not have type.
};
Basically you save the type in a typedef and then use that in A. This would error out of course if B does the T of A does not have T::type.
Related
Consider the code below:
template <typename T>
class A{
...
}
template <class U>
class B{
...
}
int main {
B<A<int>> a;
...
}
How can I get the template parameter of A (int in this case) inside B, if A<int> is the template parameter for B?
I could parametrize B as follows, but I feel like I am sending an unnecessary piece of information.
template <class AA, typename T>
class B { ... }
The reason I do not simply use template <typename T> for class B is that I have a pointer to class A inside B, and I want to use the template parameter class AA to see if that pointer is const or not, hence have the correct type for the member pointer in B.
There are several ways, depending of that you might change:
Quick way, specialize B
template <class> class B;
template <class T>
class B<A<T>>
{
// Use directly T
//...
};
Add info in A directly (as std containers do with value_type)
template <typename T>
struct A
{
using my_type = T;
};
// Then in `B<U>`, use `typename U::my_type`
Use external traits to extract information from A (as std::iterator_traits) (that also allows to handle built-in types):
template <typename T>
struct ATrait;
template <typename T>
struct ATrait<A<T>>
{
using my_type = T;
};
// Possibly a generic one
template <template <typename> class C, typename T>
struct ATrait<C<T>>
{
using my_type = T;
};
// Then in `B<U>`, use `typename ATrait<U>::my_type`
I think the following does what you want:
#include<type_traits>
template<class>
class A{};
template<class>
struct get_inner;
template<template<class> class TT, class T>
struct get_inner<TT<T>> {
using outer = TT<T>;
using inner = T;
};
template<class TT>
struct B {
using A = TT;
using inner = typename get_inner<std::decay_t<A>>::inner;
};
int main(int argc, char *argv[])
{
static_assert(std::is_const_v<typename B<const A<int>>::A>);
static_assert(!std::is_const_v<typename B<A<int>>::A>);
}
Note the std::decay_t, it wouldn't work with the const parameter directly (hence we cannot just specialize B in this way). Maybe decay_t is a bit strong but it works^^
Try this
template <typename X> class B;
template <template <typename> class XX, typename T>
class B<XX<T>>
{
// your implementation
};
B<A<int>> a;
I would like to create a templated class (C2), using as a template a class which is also templated (C1). Moreover in C2 create a variable of the same type, which was used as template of the class C1.
template <typename Ttype>
class C1{
public:
Ttype var;
}
template<class T> //class T always templated
class C2{
public:
T x;
// ? y; << variable of template type of the class T
}
int main()
{
C1<int> instanceInt;
C1<long> instanceLong;
C2<C1<int>> foo; //C2.y should be int
}
My initial implementation of the class C2 was as follows, however it results in error: identifier "Ttype" is undefined. Why doesn't compiler see the Ttype?
template <template <class Ttype> class Tparam>
class C2 {
public:
Tparam<Ttype> x;
const Ttype y;
};
So my working, but not so nice solution is using a typedef.
template <typename Ttype>
class C1{
public:
typedef Ttype Ctype
Ttype var;
}
template<class T>
class C2{
public:
typedef typename T::Ctype Ttype;
T x;
Ttype y;
}
I expect that there should be a better implementation of the same feature. Is there?
The second approach could be fixed, however, the third is not bad either.
template <typename Ttype>
class C1
{
public:
Ttype var;
};
template<template <class Ttype> class Tparam, typename T>
class C2
{
public:
Tparam<T> x;
T y;
};
void foo()
{
C2<C1,int> bar;
}
You can use template specialization
template <typename>
class C2;
template <template <typename> class C, typename T>
class C2<C<T>>
{
public:
C<T> x;
T y;
};
or you can also develop a custom type trait to extract a template argument from a type
template <typename>
struct get_tmpl_param;
template <template <typename> class C, typename T>
struct get_tmpl_param<C<T>>
{ using type = T; };
template <typename T>
using get_tmpl_param_t = typename get_tmpl_param<T>::type;
so your class C2 (without specialization) can be
template <typename T>
class C2
{
public:
T x;
get_tmpl_param_t<T> y;
};
I have a struct within a class like this
template <class T>
class a {
struct b {
int var;
b *foo(const T&);
};
int var;
};
and I want to define foo outside of struct b.
How do I do that?
template <class T>
typename a<T>::b* a<T>::b::foo(const T&)
{
//code
}
I want to specialize a constructor of a class template. This doesn't work:
template<typename T>
struct One {};
template<typename T>
struct Two {};
template<template<typename> class T, template<typename> class U>
struct Three : public T<Three<T, U>>, public U<Three<T, U>> {};
template<typename T> struct Four;
template<typename T>
struct Four
{
Four();
};
template<template<typename> class T, template<typename> class U>
Four<Three<T, U>>::Four() {}
int main(int argc, char *argv[])
{
Four<Three<One, Two> > obj;
}
but changing the class template definition to this works:
template<typename T> struct Four;
template<template<typename> class T, template<typename> class U>
struct Four<Three<T, U>>
{
Four();
};
template<template<typename> class T, template<typename> class U>
Four<Three<T, U>>::Four() {}
This seems like I'm specializing the entire class template. However I want to specialize only the constructor as in the code above - the one that doesn't work. Why can't I specialize the constructor of Four for just Three (I'm not changing the signature of the ctor of the class template)?
You can't. You must specialize the whole class. But.. you can use inheritance as a work around:
#include <iostream>
class something {};
template <typename T> class hidden_base {
public: hidden_base() {a = 1;}
protected: int a;
};
template<> class hidden_base<something> {
public: hidden_base() {a = 2;}
protected: int a;
};
template <typename T>
class your_class : public hidden_base<T> {
public:
void lots();
void of();
void other();
void member();
void functions();
void here();
void show_a() {std::cout << hidden_base<T>::a << std::endl;}
};
int main() {
your_class<long>().show_a();
your_class<int>().show_a();
your_class<something>().show_a();
}
This will print:
1
1
2
Consider the following:
template <typename T>
class Base {
public:
template <typename U>
class Nested { };
};
template <typename T>
class Derived : public Base<T> {
public:
//How do we typedef of redefine Base<T>::Nested?
using Base<T>::Nested; //This does not work
using Base<T>::template<typename U> Nested; //Cannot do this either
typedef typename Base<T>::template<typename U> Nested Nested; //Nope..
//now we want to use the Nested class here
template <typename U>
Class NestedDerived : public Nested { };
//or like this:
Nested<int> nestedVar; // obviously does not work
};
How to use the templated Nested class in the Derived class? Is this possible to do in current version of C++ standard?
Actually using works as advertised, it just doesn't get rid of the dependent-name issue in the template and it can't currently alias templates directly (will be fixed in C++0x):
template <class T>
struct Base {
template <class U> struct Nested {};
};
template <class T>
struct Derived : Base<T> {
using Base<T>::Nested;
// need to prefix Nested with template because
// it is a dependent template:
struct X : Base<T>::template Nested<int> {};
// same here:
template<class U>
struct Y : Base<T>::template Nested<U> {};
// data member, typename is needed here:
typename Base<T>::template Nested<int> data;
};
void f() {
Derived<int>::Nested<int> n; // works fine outside
}
There is another possible gotcha when using Derived<T>::Nested in templates, but again that is a dependent-name issue, not inheritance-related:
template<class T>
void g() {
// Nested is a dependent type and a dependent template, thus
// we need 'typename' and 'template':
typedef typename Derived<T>::template Nested<int> NestedInt;
}
Just remember that names that depend on template arguments have to be
prefixed with typename if its a dependent type: typename A<T>::B
directly prefixed with template if its a dependent template: A<T>::template f<int>()
both if both: typename A<T>::template B<int>
typename is illegal in base-class-lists: template<class T> struct A : B<T>, C<T>::template D<int> {};
This seems to work:
(EDIT: added some more lines to show the first template statement. And thanks to Samir Talwar for correcting my formatting!)
template <typename T, typename U>
class Derived : public Base<T> {
public:
typedef typename Base<T>::template Nested<U> Nested;
class NestedDerived : public Nested { };
Nested nestedVar;
};
Try this:
template <typename T>
class Base {
public:
template <typename U>
class Nested { };
};
template <typename T>
class Derived : public Base<T> {
public:
//How do we typedef of redefine Base<T>::Nested?
//using Base<T>::Nested; //This does not work
//using Base<T>::template<typename U> Nested; //Cannot do this either
//typedef typename Base<T>::template<typename U> Nested Nested; //Nope..
//now we want to use the Nested class here
template <typename U>
class NestedDerived : public Base<T>::template Nested<U> { };
};
int main()
{
Base<int>::Nested<double> nested;
Derived<int>::NestedDerived<double> nested_derived;
return 0;
}
Compiled fine using gcc 4.3.3 on slackware 13
I'm still not 100% sure what you want, but you could try.
This compiled on Visual Studio
template <typename T>
class Base {
public:
template <typename U>
class Nested { };
};
template <typename T>
class Derived : public Base<T> {
public:
//now we want to use the Nested class here
template <typename U>
class NestedDerived : public Nested<U> { };
};
int _tmain(int argc, _TCHAR* argv[])
{
Base<int>::Nested<double> blah2;
Derived<int>::NestedDerived<int> blah;
return 0;
}