Nested template using/typdef - c++

Say I have this setup:
template<typename T1>
struct A {
template<typename T2>
struct B {
using type = int;
};
};
I'd like to be able to form a typdef/using:
template<typename T1,typename T2>
using type2 = A<T1>::B<T2>::type;
//... and use like
type2<int,char> foo;
GCC complains that I need typename A<T1>::B<T2>::type instead, and afterwards complains that it expects ";" before "<" after B (i.e. typename A<T1>::B)
is there no way to use "using" with nested templates?

Switch from
using type2 = A<T1>::B<T2>::type;
to
using type2 = typename A<T1>::template B<T2>::type;

Note that B is a templated class and type is enclosed in a templated class, hence use the following
#include <iostream>
template<typename T1>
struct A {
template<typename T2>
struct B {
using type = int;
};
};
template<typename T1,typename T2>
using type2 = typename A<T1>::template B<T2>::type;
int main()
{
type2<int,char> foo =2;
std::cout << foo;
}

Related

C++: Way around dependent templates

I have a class template like this:
template <typename T1, typename T2>
class ClassName {
// Members variables and Functions based on the template parameter types
};
(T1, T2) can either be (class A, class B) or (class C, class D) only.
So, T1 alone is enough to determine T2.
Is there any way to only take T1 as a parameter and write the same class? If yes, how?
If your template only depends on a single parameter, you should not declare it with 2 parameters. You can use std::conditional together with std::is_same to declare conditional aliases.
If you want:
(T1, T2) can either be (class A, class B) or (class C, class D) only
If "only" is meant as: User only ever instantiates for A or C and in that case T2 should be B / D:
#include <type_traits>
struct A {};
struct B {};
struct D {};
template <typename T>
struct Foo {
using T1 = T;
using T2 = std::conditional_t<std::is_same_v<A, T>, B, D>;
};
Foo<A>::T2 is B and Foo<C>::T2 is D. Actually Foo<T>::T2 is D for any T that is not A. In other words, as mentioned above, the premise is that it is only instantiated for either A or C. If the template itself should make sure that only instantiations for A or C are valid, you might want to add a static_assert (again using std::is_same to check that T is among the allowed types).
Make an enumeration of your configurations:
enum class ClassConfigEnum { AB, CD};
template<ClassConfigEnum config> struct ClassConfig;
template<> struct ClassConfig<AB> {
using T1 = A;
using T2 = B;
};
template<> struct ClassConfig<CD> {
using T1 = C;
using T2 = D;
};
And then have the class use the enumerated configuration
template <ClassConfigEnum config>
class ClassName {
using T1 = ClassConfig<config>::typename T1;
using T2 = ClassConfig<config>::typename T2;
};
You can write a type trait:
#include <iostream>
#include <type_traits>
struct A {};
struct B {};
struct C {};
struct D {};
template <typename Type> struct Dependent {};
template<>
struct Dependent<A> {
using type = B;
};
template<>
struct Dependent<C> {
using type = D;
};
template <typename Type>
class ClassName {
using Dependent = typename Dependent<Type>::type;
};
int main()
{
static_assert(std::is_same<Dependent<A>::type, B>::value, "");
static_assert(std::is_same<Dependent<C>::type, D>::value, "");
// Dependent<B>::type a; error: 'type' is not a member of 'Dependent<B>'
}

How to define a typedef which is dependent on a template argument's typedef

I'd like to make a typedef which is dependent on the existence of a typedef in a template argument:
struct foo
{
using MyType = int;
};
template <typename T = foo>
struct bar
{
// Pseudo code
#if T::MyType is defined
using MyType = T::MyType;
#else
using MyType = double;
#endif
};
Is there a way to get it to work using std::conditional or something else in C++14?
There is, with a bit of sfinae.
template<class, typename Fallback, typename = void>
struct type_or_default {
using type = Fallback;
};
template<class C, typename F>
struct type_or_default<C, F, std::void_t<typename C::type>> {
using type = typename C::type;
};
This uses the standard convention where template meta-functions expose a member name type, but you can adapt it for your own naming needs. The only non-C++14 bit here is std::void_t, but an equivalent thing can be implemented in C++14 (it just can't be put into namespace std). You use it in your class like this:
template <typename T = foo>
struct bar
{
using type = typename type_or_default<T, double>::type;
};
What happens here is that the compiler does its pattern matching when choosing a template specialization. If the class C has a member type, then the partial specialization we provided will be considered more specialized, and as such chosen. Otherwise (if substitution fails when checking the specialization), the primary template is always there to fall back to.
Live program to tinker with.
My five cents to this question.
#include <type_traits>
template <typename T, typename DefaultType>
struct CalculateMyType {
template <typename C>
static typename C::MyType test(typename C::MyType*);
template <typename>
static DefaultType test(...);
typedef decltype(test<T>(nullptr)) MyType;
};
struct foo
{
using MyType = int;
};
template <typename T = foo>
struct bar
{
using MyType = typename CalculateMyType<T, double>::MyType;
};
struct baz
{
};
struct quux
{
using MyType = float;
};
#include <iostream>
#include <typeinfo>
template <typename>
struct TypeToStr;
template<> struct TypeToStr<double> { const char * name = "double"; };
template<> struct TypeToStr<float> { const char * name = "float"; };
template<> struct TypeToStr<int> { const char * name = "int"; };
int main() {
std::cout << "bar<foo>::MyType = " << TypeToStr<bar<foo>::MyType>().name << std::endl;
std::cout << "bar<baz>::MyType = " << TypeToStr<bar<baz>::MyType>().name << std::endl;
std::cout << "bar<quux>::MyType = " << TypeToStr<bar<quux>::MyType>().name << std::endl;
}
Live program

Access type member

In my example I have a class Foo<T>. In my function test I need to get the template parameter of Foo otherwise the normal type. First I started to use std::conditional but forgot that the template parameters must all be valid, no matter which one is picked. Is the only way to create a type-specialisation for non-Foo types?
Example
#include <type_traits>
template <typename TYPE>
class Foo
{
public:
using M = TYPE;
};
template <typename T>
void test(const T& a)
{
// actually I would have used !is_foo<T>::value for the first arg
// but this check is fine to minimise the example
using MY_TYPE = typename std::conditional<
std::is_same<T, int>::value,
T,
typename T::M>::type; // <---Error: error: type 'int' cannot be used prior to '::' because it has no members
}
int main()
{
test(Foo<int>()); // MY_TYPE must be int
test(int()); // MY_TYPE must be int
return 0;
}
Well you could make an UnFoo helper to get the right type for you:
template <typename T>
struct UnFoo {
using type = T;
};
template <typename T>
struct UnFoo<Foo<T>> {
using type = T;
};
template <typename T>
void test(const T& a)
{
using MY_TYPE = typename UnFoo<T>::type; //maybe with a helper to get rid of typename
}
Another option would be to write an overload for Foo<T> and have it delegate to the other function, but that depends on what your real test function does.
You can do some void_t magic to allow SFINAE to figure help you out:
#include <type_traits>
#include <iostream>
#include <typeinfo>
template <typename TYPE>
class Foo
{
public:
using M = TYPE;
};
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
// primary template handles types that have no nested ::T member:
template< class T, class = void_t<> >
struct M_or_T { using type = T; };
// specialization recognizes types that do have a nested ::T member:
template< class T >
struct M_or_T<T, void_t<typename T::M>> { using type = typename T::M; };
template <typename T>
void test(const T& a)
{
using MY_TYPE = typename M_or_T<T>::type;
std::cout << typeid(MY_TYPE).name() << "\n";
}
int main()
{
test(Foo<int>()); // MY_TYPE must be int
test(int()); // MY_TYPE must be int
return 0;
}
What happens is that the second overload of M_or_T substitution fails for int (and for any type without a type member M) and thus the first overload is chosen. For types which have a type member M, a more specialized second overload is chosen.
#include <type_traits>
template <typename TYPE>
class Foo
{
public:
using M = TYPE;
};
template <typename T>
void test(const Foo<T>& a)
{
using MY_TYPE = Foo<T>::M;
testOther<MY_TYPE>(a);
}
template <typename T>
void test(const T& a)
{
using MY_TYPE = T;
testOther<MY_TYPE>(a);
}
template <typename T, typename S>
void testOther(const S& a)
{
// do stuff
}
int main()
{
test(Foo<int>()); // MY_TYPE must be int
test(int()); // MY_TYPE must be int
return 0;
}
I'm not exactly sure what you wanted, but I hope this is what you wanted. It might be a bit off. I didn't compile this.

specialize template<typename T, template<typename> class U>

I have a problem with nested templates and their template specialization. Given the following classes:
A small template class
template<class U>
class T {
public:
T(){}
virtual ~T (){}
};
And some kind of nested template
template<typename T, template<typename> class U>
class A {
public:
void foo()
{
std::cerr << "A generic foo";
}
};
And a small main.cpp
int main(int argc, const char *argv[])
{
A<int,T> *a = new A<int,T>;
a->foo();
//This wont work:
A<double,T*> *b = new A<double,T*>;
b->foo();
return 0;
}
Now I need a specialization if U is a pointer:
A<double,T*> *b = new A<double,T*>;
b->foo();
How to achieve this? I tried something like:
template<typename T, template<typename> class U>
class A< T, U* >
{
public:
void foo()
{
std::cerr << "A specialized foo";
}
};
But it just resolves in
A.h:18:16: Error: Templateargument 2 is invalid
What you're tying to do is not possible, because T* has no meaning. Neither is it a proper type, nor does it match a template, which requires additional parameters. If U were to represent T*, what would U<int> be? You probably mean T<int>* but that doesn't match your declaration, so there is no way to plug that type into A.
Since you asked for a way to get around this, from the top of my head, something like this.
Accept a third template argument to A, which I would call Expander and set it by default to this:
template <typename T> struct Expander {
typedef T type;
};
Then, when invoking A you could say
A<int,T> normal;
A<int,T,PtrExpander> pointer;
with
template <typename T> struct PtrExpander {
typedef T* type;
};
and A would be:
template<typename T, template<typename> class U, template <typename> class E = Expander> class A {
typedef typename E<U<Your_Args_to_U> >::type;

Conditional compile-time inclusion/exclusion of code based on template argument(s)?

Consider the following class, with the inner struct Y being used as a type, eg. in templates, later on:
template<int I>
class X{
template<class T1>
struct Y{};
template<class T1, class T2>
struct Y{};
};
Now, this example will obviously not compile, with the error that the second X<I>::Y has already been defined or that it has too many template parameters.
I'd like to resolve that without (extra) partial specialization, since the int I parameter isn't the only one and the position of it can differ in different partial specializations (my actual struct looks more like this, the above is just for simplicity of the question), so I'd like one class fits every I solution.
My first thought was obviously enable_if, but that seems to fail on me, eg. I still get the same errors:
// assuming C++11 support, else use boost
#include <type_traits>
template<int I>
class X{
template<class T1, class = std::enable_if<I==1>::type>
struct Y{};
template<class T1, class T2, class = std::enable_if<I==2>::type>
struct Y{};
};
So, since enable_if fails, I hope there is another way to achieve the following compile time check:
template<int I>
class X{
__include_if(I == 1){
template<class T1>
struct Y{};
}
__include_if(I == 2){
template<class T1, class T2>
struct Y{};
}
};
It would just be to save me a lot of code duplication, but I'd be really happy if it was somehow possible.
Edit: Sadly, I can't use the obvious: variadic templates, as I'm using Visual Studio 2010, so only the C++0x stuff that is supported there I can use. :/
There are two problems here:
enable_if works with partial specialization, not primary templates.
The number of externally-visible arguments is determined by the primary template, of which there may be only one.
Answer 1.
As you suggested in chat, a linked list of templates can emulate the variadic parameter pack.
template<int I>
class X{
template<class list, class = void>
struct Y;
template<class list>
struct Y< list, typename std::enable_if<I==1>::type > {
typedef typename list::type t1;
};
template<class list>
struct Y< list, typename std::enable_if<I==2>::type > {
typedef typename list::type t1;
typedef typename list::next::type t2;
};
};
If you end up with next::next::next garbage, it's easy to write a metafunction, or use Boost MPL.
Answer 2.
The different-arity templates can be named similarly but still stay distinct if they are nested inside the SFINAE-controlled type.
template<int I>
class X{
template<typename = void, typename = void>
struct Z;
template<typename v>
struct Z< v, typename std::enable_if<I==1>::type > {
template<class T1>
struct Y{};
};
template<typename v>
struct Z< v, typename std::enable_if<I==2>::type > {
template<class T1, class T2>
struct Y{};
};
};
X<1>::Z<>::Y< int > a;
X<2>::Z<>::Y< char, double > b;
Here you go:
http://ideone.com/AdEfl
And the code:
#include <iostream>
template <int I>
struct Traits
{
struct inner{};
};
template <>
struct Traits<1>
{
struct inner{
template<class T1>
struct impl{
impl() { std::cout << "impl<T1>" << std::endl; }
};
};
};
template <>
struct Traits<2>
{
struct inner{
template<class T1, class T2>
struct impl{
impl() { std::cout << "impl<T1, T2>" << std::endl; }
};
};
};
template<class T>
struct Test{};
template<class T, class K>
struct Foo{};
template<int I>
struct arg{};
template<
template<class, class> class T,
class P1, int I
>
struct Test< T<P1, arg<I> > >{
typedef typename Traits<I>::inner inner;
};
template<
template<class, class> class T,
class P2, int I
>
struct Test< T<arg<I>, P2 > >{
typedef typename Traits<I>::inner inner;
};
// and a bunch of other partial specializations
int main(){
typename Test<Foo<int, arg<1> > >::inner::impl<int> b;
typename Test<Foo<int, arg<2> > >::inner::impl<int, double> c;
}
Explanation: Basically it's an extension of the idea of partial specialization, however the difference is that rather than specializing within Test, delegate to a specific class that can be specialized on I alone. That way you only need to define versions of inner for each I once. Then multiple specializations of Test can re-use. The inner holder is used to make the typedef in the Test class easier to handle.
EDIT: here is a test case that shows what happens if you pass in the wrong number of template arguments: http://ideone.com/QzgNP
Can you try below (it is not partial specialization):
template<int I>
class X
{
};
template<>
class X<1>
{
template<class T1>
struct Y{};
};
template<>
class X<2>
{
template<class T1, class T2>
struct Y{};
};
I doubt if the answer is that simple !!
Edit (Mocking Partial specialization):
#Xeo, I was able to compile following code and seems to be fullfilling.
template<int I>
struct X
{
struct Unused {}; // this mocking structure will never be used
template<class T1, class T2 = Unused> // if 2 params passed-->ok; else default='Unused'
struct Y{};
template<class T1>
struct Y<T1, Unused>{}; // This is specialization of above, define it your way
};
int main()
{
X<1>::Y<int> o1; // Y<T1 = int, T2 = Unused> called
X<2>::Y<int, float> o2; // Y<T1 = int, T2 = float> called
}
Here, however you can use X<1>, X<2> interchangeably. But in the broader example you mentioned, that is irrelevant. Still if you need, you can put checks for I = 1 and I = 2.
How about this approach - http://sergey-miryanov.blogspot.com/2009/03/template-class-overriding.html? (sorry for russian)
You can use a meta function (here: inlined boost::mpl::if_c, but could be arbitrarily complex) to select the one you want. You need some scaffolding to be able to use constructors, though:
template <int I>
class X {
template <typename T1>
class YforIeq1 { /* meat of the class */ };
template <typename T1, typename T2>
class YforIeq2 { /* meat of the class */ };
public:
template <typename T1, typename T2=boost::none_t/*e.g.*/>
struct Y : boost::mpl::if_c<I==1,YforIeq1<T1>,YforIeq2<T1,T2> >::type {
typedef typename mpl::if_c<I==1,YforIeq1<T1>,YforIeq2<T1,T2> >::type YBase;
/* ctor forwarding: C++0x */
using YBase::YBase;
/* ctor forwarding: C++03 (runs into perfect fwd'ing problem)*/
Y() : YBase() {}
template <typename A1>
Y(const A1&a1) : YBase(a1) {}
template <typename A1, typename A2>
Y(const A1&a1, const A2&a2) : YBase(a1,a2) {}
// ...
};
};
If there's a problem with both YforIeqN being instantiated for each X, then you can try wrapping them as a nullary meta function (something along the way mpl::apply does) and use mpl::eval_if_c.