C++ dynamic downcasting to class template having template template parameter being a class template or an alias template -


i hope title makes sense. miss vocabulary express correctly.

well, exemple more clear.

problem me is: dynamic downcasting returns 0 @ run time in of following cases (written in comments). i'd know if it's correct behaviour (using c++11), why, , can make work. apparently, templated , a::a_templated treated different classes, despite being defined identical using alias "using". problem doesn't appear simple typedef alias.

template <class t> class templated {};  class {     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 way see problem, more clear. i'm facing after trying avoid example above. following example's says bogdan pointed out. find frustrating fact compiler can't resolve templated templated_alias. i'm wondering if compilation option exists, 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> equivalent templated<int>     b<templated_alias> b2;//compilation error: implicit instantiation of undefined template b<templated_alias>     //which means: templated_alias not equivalent templated } 

thanks bogdan's trick, , after little nose-bleeding, managed find kind of solution. idea build class in charge of 'filtering' potential aliases of template classes. needs 1 specification per template class needed 'filtered'. main drawback of method filtering needs used everywhere template classes used template parameters in order consistent.

//classes dealt  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 : public a_base {     void foo() {} };  //here starts 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;     = 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;      = 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;      = 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 above trick. ran different problems. can't absolutely sure it's related it's likely. compiler seems struggle correctly build 'dynamic table'. asked problem @ c++ can make type_info::hash_code differs 2 (supposedly) same objects may bad, wouldn't recommend using trick clang 3.1 .

clang's behaviour correct.

a::a_type equivalent int according [7.1.3p1] in standard:

[...] within scope of declaration, typedef-name syntactically equivalent keyword , names type associated identifier in way described in clause 8. typedef-name synonym type. typedef-name not introduce new type way class declaration (9.1) or enum declaration does.

a::a_templated<int> equivalent templated<int> according [14.5.7p2]:

when template-id refers specialization of alias template, equivalent associated type obtained substitution of template-arguments template-parameters in type-id of alias template.

however, a::a_templated not equivalent templated, according [14.5.7p1]:

[...] name of alias template template-name.

this means a::a_templated , templated 2 different templates, test_templated<a::a_templated> , test_templated<templated> different specializations of test_templated, casts return null pointers correct in doing so.

gcc 5.1.0 doesn't handle correctly. clang 3.6.0 , msvc 14 rc handle correctly.


all references working draft n4431.

note there active core working group issue regarding behaviour - issue 1286. author says intention introduce standard wording make such cases work way expected, is, make alias template equivalent 1 referenced in type-id. there's note may 2015 in there, indicating issue receiving attention, it's not there yet.


in terms of "making work", it's difficult give solutions without knowing practical needs are, i'd try make test_templated depend on specializations of templated, rather template itself, is, declare like

template<class t> class test_templated : public test_base { /* ... */ }; 

and use

test = new test_templated<templated<int>>; std::cout << dynamic_cast< test_templated<templated<int>>* >(test) << std::endl; //ok std::cout << dynamic_cast< test_templated<a::a_templated<int>>* >(test) << std::endl; //also ok 

you wrap adding level of indirection, if helps in way:

template<template<class> class tt, class t> using make_test_templated = test_templated<tt<t>>; 

and use this:

test = new make_test_templated<a::a_templated, long>; std::cout << dynamic_cast< make_test_templated<a::a_templated, long>* >(test) << std::endl; //ok std::cout << dynamic_cast< make_test_templated<templated, long>* >(test) << std::endl; //also ok 

anyway, think key try use fact specializations equivalent.


alright, based on latest update, here's hack addressing problem in second code sample: change explicit specialization b<templated> partial specialization matches if given template generates same specialization templated when instantiated argument (let's int example).

how's confusing sentence? sorry. here's code sample becomes above changes:

#include <iostream> #include <type_traits>  template<class> class templated { }; template<class t> using templated_alias = templated<t>; template<class> class templated2 { };  // helper trait 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<class> class, class = std::true_type> class b; template<template<class> class tt> class b<tt, is_same_template_t<tt, templated>> { public:    void foo(templated<int>) { std::cout << "b<templated>::foo\n"; } };  int main() {    b<templated> b1;    b1.foo(templated<int>());    b1.foo(templated_alias<int>());    b<templated_alias> b2; // works fine now, , next 2 lines.    b2.foo(templated<int>());    b2.foo(templated_alias<int>());    // b<templated2> b22; // error trying instantiate primary template b. } 

note have make sure is_same_template_t used check templates can instantiated int argument (change int whatever need, of course). if want make more generic, can include type on templates need instantiated in trait's parameter list, this:

template<template<class> class tt1, template<class> class tt2, class t> using is_same_template_t = typename std::is_same<tt1<t>, tt2<t>>::type; 

and use this:

is_same_template_t<tt, templated, int> 

Comments

Popular posts from this blog

Magento/PHP - Get phones on all members in a customer group -

php - Bypass Geo Redirect for specific directories -

php - .htaccess mod_rewrite for dynamic url which has domain names -