I hope the title makes sense. I probably miss vocabulary to express it correctly.
Well, an exemple will probably be more clear.
Problem for me is: dynamic downcasting returns 0 at run time in some of the following cases (written in comments). I'd like to know if it's a correct behaviour (using C++11), also why, and what can I do to make it work. Apparently, Templated and A::A_templated are treated as different classes, despite being defined as identical by using alias "using". Problem doesn't appear for simple typedef alias.
template <class T>
class Templated {};
class A {
public :
typedef int A_Type;
template <class T>
using A_Templated = Templated<T>;
};
class Test_base {
public :
Test_base() {}
virtual void foo()=0;
};
template <class T>
class Test_Type : public Test_base {
public :
Test_Type() {}
void foo() {}
};
template < template <class T> class TT >
class Test_Templated : public Test_base {
public :
Test_Templated() {}
void foo() {}
};
int main() {
Test_base* test;
test = new Test_Type<int>;
std::cout << dynamic_cast< Test_Type<int>* >(test) << std::endl;//-->ok
std::cout << dynamic_cast< Test_Type<A::A_Type>* >(test) << std::endl;//-->ok
test = new Test_Templated<Templated>;
std::cout << dynamic_cast< Test_Templated<Templated>* >(test) << std::endl;//-->ok
std::cout << dynamic_cast< Test_Templated<A::A_Templated>* >(test) << std::endl;//--> returns 0 !
test = new Test_Templated<A::A_Templated>;
std::cout << dynamic_cast< Test_Templated<A::A_Templated>* >(test) << std::endl;//-->ok
std::cout << dynamic_cast< Test_Templated<Templated>* >(test) << std::endl;//--> returns 0 !
}
I propose another way to see the problem, this is probably more clear. I'm facing it after trying to avoid the example above. The following example's basically says what Bogdan pointed out. I find very frustrating the fact the compiler can't resolve Templated with Templated_alias. I'm wondering if a compilation option exists, which can sort of force type resolving through template aliases.
template <class T>
class Templated {};
template <class T>
using Templated_alias = Templated<T>;
template < template <class T> class TT >
class B;
template <>
class B<Templated> {
public :
void foo(Templated<int> _arg) {}
};
int main() {
B<Templated> b1;
b1.foo(Templated<int>());
b1.foo(Templated_alias<int>());//compiles => Templated_alias<int> is equivalent to Templated<int>
B<Templated_alias> b2;//Compilation error: Implicit instantiation of undefined template B<Templated_alias>
//which means: Templated_alias is not equivalent to Templated
}
Thanks to Bogdan's trick, and after some little nose-bleeding, I managed to find some kind of solution. The idea is to build a class in charge of 'filtering' potential aliases of template classes. It needs one specification per template class needed to be 'filtered'. Main drawback of the method is that filtering thus needs to be used everywhere template classes are used as template parameters in order to be consistent.
//Classes to be dealt with
template <class T>
class Templated {};
template <class T>
class Templated2 {};
template <class T>
using Templated_alias = Templated<T>;
class A_base {
virtual void foo()=0;
};
template <template <class T> class TT>
class A : public A_base {
void foo() {}
};
//Here starts the trick definition
template<template<class> class TT1, template<class> class TT2>
using is_same_template_t = typename std::is_same<TT1<int>, TT2<int> >::type;
//Template Template aliasing
template < template <class T> class TT >
class TT_aliasing {
public :
template <class T>
using Class_T = TT<T>;
};
//Template Template Alias Filtering
template < template <class T> class TT, class = std::true_type>
class TT_AF {
public :
template <class T>
using Class_T = TT<T>;
};
template < template <class T> class TT >
class TT_AF<TT, is_same_template_t<TT, Templated> > : public TT_aliasing<Templated> {};
int main() {
A_base* a;
a = new A< TT_AF<Templated>::Class_T >();
std::cout << dynamic_cast< A< TT_AF<Templated>::Class_T >* >(a) << std::endl;
std::cout << dynamic_cast< A< TT_AF<Templated_alias>::Class_T >* >(a) << std::endl;
std::cout << dynamic_cast< A< TT_AF<Templated2>::Class_T >* >(a) << std::endl;
std::cout << "---------------" << std::endl;
a = new A< TT_AF<Templated_alias>::Class_T >();
std::cout << dynamic_cast< A< TT_AF<Templated>::Class_T >* >(a) << std::endl;
std::cout << dynamic_cast< A< TT_AF<Templated_alias>::Class_T >* >(a) << std::endl;
std::cout << dynamic_cast< A< TT_AF<Templated2>::Class_T >* >(a) << std::endl;
std::cout << "---------------" << std::endl;
a = new A< TT_AF<Templated2>::Class_T >();
std::cout << dynamic_cast< A< TT_AF<Templated>::Class_T >* >(a) << std::endl;
std::cout << dynamic_cast< A< TT_AF<Templated_alias>::Class_T >* >(a) << std::endl;
std::cout << dynamic_cast< A< TT_AF<Templated2>::Class_T >* >(a) << std::endl;
A< TT_AF<Templated>::Class_T > a1;
A< TT_AF<Templated_alias>::Class_T > a2;
a1 = a2;
A< TT_AF<Templated2>::Class_T > a3;
//a1 = a3;//no viable overloaded '='
}
Output gives:
0x600000014ba0
0x600000014ba0
0x0
---------------
0x600000014bb0
0x600000014bb0
0x0
---------------
0x0
0x0
0x600000014bc0
After using the above trick. I ran into different problems. Can't be absolutely sure it's related but it's very likely. Compiler seems to struggle to correctly build the 'dynamic table'. I asked for this problem at C++ what can make type_info::hash_code differs for two (supposedly) same objects May be my bad, but for now I wouldn't recommend using the trick with Clang 3.1 .