Different type based on template type - c++

I have ::Class1 and ::Class2, I'd like to create template function that gets either first or second one and then based on selected class use other classes defined in different namespace i.e. NameSpace::Class1, NameSpace::Class2. Is there way to do it in C++?
For example:
namespace NameSpace
{
class Class1 {}; class Class2 {};
}
template <class T> // example Class1 or Class2
void f(T object) {
NameSpace::T obj; // Something like this, but it doesn't work
}

NameSpace::T doesn't work as T isn't the name Class1 or Class2, it represents the type. Templates don't work on textual substitution like that.
You could provide a trait to translate between the type in the global namespace and that from NameSpace:
struct Class1{}; struct Class2 {};
namespace NameSpace
{
class Class1 {}; class Class2 {};
template <typename T> struct translate;
template<> struct translate<::Class1> {
using type = Class1;
};
template<> struct translate<::Class2> {
using type = Class2;
};
template <typename T>
using translate_t = typename translate<T>::type;
}
You would use this like so:
template <class T>
void f(T object) {
using Translated = NameSpace::translate_t<T>;
Translated obj;
}

You can specialize a struct to map one type to another
template <typename T>
struct FromType {};
template <>
struct FromType<Class1>
{
typedef ns::Class1 type;
}
template <>
struct FromType<Class2>
{
typedef ns::Class2 type;
}
This can then be used in a template function by referring to the resulting type as
typename FromType<T>::type
Note that this will also give a compile error if you attempt to use a type other than Class1 or Class2.

Just omnit the NameSpace in NameSpace::T. The namespace must be defined in the function f call. The following example compiles.
namespace NameSpace
{
class Class1 {}; class Class2 {};
}
template <class T> // example Class1 or Class2
void f(T object) {
T obj;
}
int main()
{
NameSpace::Class1 x;
f(x);
return 0;
}

Related

Partial template specialization using nested (undefined yet) type of a forward-declared class

There is a way to make a partial template specialization for a forward-declared (incomplete) type (answer).
But after seeing the mentioned question I wondered if it is possible to define a partial specialization for a class template using an incomplete nested (and possibly private) class.
In C++ currently one can't forward-declare a nested class without defining the class:
class undefined;
class undefined::foo; // impossibru
With some hacks I made a working code (for a sake of research): https://godbolt.org/z/9W8nfhx8P
#include <iostream>
template <typename T, typename = T>
struct specialize;
// workaround to get to a nested foo
template <typename T, typename...>
struct mem_foo
{
// error: 'struct undefined::foo' is private within this context
using type = typename T::foo;
};
class undefined;
// class undefined::foo; // impossibru
template <typename MemFoo>
struct specialize<typename mem_foo<undefined, MemFoo>::type, MemFoo>
{
void operator()(const MemFoo &f) const
{
// this will compile however
std::cout << f.name << std::endl;
}
};
#include <string>
class undefined
{
private: // will not compile without friend
struct foo{
std::string name = "John Cena";
};
friend struct mem_foo<undefined, foo>; // ugly
// friend struct specialize<foo>; // this is irrelevant, but would be nicer than mem_foo
public:
static foo get() { return {}; }
};
int main()
{
specialize</*undefined::foo*/decltype(undefined::get())>{}(undefined::get());
return 0;
}
But for a private types an ugly friend is used. friend struct specialize<undefined::foo>; would be more semantically appealing.
Is there another or more elegant solution?
A more elegant/less convoluted solution: https://godbolt.org/z/3vrfPWP5f
#include <iostream>
template <typename T, typename = T>
struct specialize;
template <typename T, typename ...>
struct defer_instantiation
{
using type = T;
};
template <typename T, typename ... R>
using defer_instantiation_t = typename defer_instantiation<T, R...>::type;
class undefined;
// class undefined::foo; // impossibru
template <typename MemFoo>
struct specialize<typename defer_instantiation_t<undefined, MemFoo>::foo, MemFoo>
{
void operator()(const MemFoo &f) const
{
// this will compile however
std::cout << f.name << std::endl;
}
};
#include <string>
class undefined
{
private:
struct foo{
std::string name = "John Cena";
};
friend struct specialize<foo>; // this is irrelevant, but would be nicer than mem_foo
public:
static foo get() { return {}; }
};
int main()
{
specialize</*undefined::foo*/decltype(undefined::get())>{}(undefined::get());
return 0;
}
It allowes to reference yet non-existing member types of a yet incomplete class via a deferred template instantiation.

If template parameter AA is a templatized class A<T> itself, is it possible to get the template parameter (T) of this templatized class?

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;

Member function of nested class returns type of nested class

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
}

Can we specialize a template class for a templated class?

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;
}

How to create new typename from the typename pass in a template class

Suppose I am having a template class
template <class DATA>
class Stack {
//Some implementation
}
Inside this stack class I am calling a utility class which is also template. But datatype its handling is of type UltityDATA. That is if we create the object of class stack using following code
stack<MyData> s
Internally it should call UltityMyData. I dont want to expose UltityMyData stucture to the clients. I have already written implementation for coverting MyData to UltityMyData . Only My requirement is how to convert DATA typename to UtilityDATA typename when I am calling my library class.
I have wrritten following code as per your suggestion
#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>
using namespace std;
struct RTI
{
int a;
};
struct DDSRTI
{
int b;
};
// other specialization you might need in the future
template<class Data>
struct DDS
{
typedef DDSData type;
};
template <class T>
class MyStack {
private:
T a;
public:
MyStack()
{
// cout<< a;
}
};
#define STACK(T) Stack<DDS##T>
template <class T>
class Stack {
private:
Stack<T> a;
STACK(T) b;
public:
Stack()
{
///cout<< a;
}
};
But I am getting error as error: 'DDST' was not declared in this scope
Basically preprocessor only appending two values and creating a new type. As per my understanding template will be convert at the time of compilation. DDS#T its taking as a new data type not as template type.
You can have a struct specializing a type definition according to your needs
// non specialized type
template<typename T>
struct UtilType {};
// specialization for DATA
template<>
struct UtilType<DATA>
{
typedef UtilityDATA type;
};
// other specialization you might need in the future
template<>
struct UtilType<NewType>
{
typedef UtilityNewType type;
};
You would then use this helper class as so
template<typename T>
class Stack
{
// .....
typedef typename UtilType<T>::type dataType; //converts DATA typename to UtilityDATA
// .....
}
You could use a traits pattern:
template <class DATA, class TRAITS>
class Stack
{
//Some implementation
}
and instanciate like this:
stack<MyData, UtilityMyData> s;
However, this will require your users to explicitly name the utility class. If you don't mind using the pre-processor you could use a macro:
#define STACK(T) Stack<T, Utility##T>
And then you'd write:
STACK(MyData) s;
It's not pretty, but it might be acceptable to your users
Maybe you can just move it to some internal template structure?
template <class DATA>
class Stack {
public:
template <class Data>
struct UtilData {
template <class... Args>
UtilData(Args&&... args) : d{std::forward<From>(args)...} {}
// other operators
Data d;
};
void push(DATA&& d) {
s.push(UtilData<DATA>{d});
}
std::stack<UtilData<DATA>> s;
};
Update: Sorry, I misunderstood your question. For some concrete types MyData and UtilMyData you can use boost::mpl::map:
using boost::mpl::pair;
using boost::mpl::map;
using boost::mpl::at;
typedef map<pair<SomeOther, Some>/*, other pairs of types here*/> TypeMap;
at<TypeMap, SomeOther>::type s; // s has type Some