VS2013 Variadic Templates Crash



  • Hi,
    da ich jetzt mit VS2013 endlich auch mal mit Variadic Templates spielen darf, hab ich mir vorgenommen, mich mal tiefer mit Template Meta Programming zu beschaeftigen; gerade erst angefangen, bitte nicht hauen, kann man sicher besser machen.

    #include <iostream>
    
    template<typename ValType, ValType start, template <typename T, T, T> class Operator, ValType ... args>
    struct calc;
    
    template<typename ValType, ValType start, template <typename T, T, T> class Operator>
    struct calc<ValType, start, Operator>
    {
    	static const ValType value = start;
    };
    
    template<typename ValType, ValType start, template <typename T, T, T> class Operator, ValType current, ValType ... tail>
    struct calc<ValType, start, Operator, current, tail...>
    {
    	static const ValType value = Operator<ValType, calc<ValType, start, Operator, tail...>::value, current>::value;
    };
    
    template<typename ValType, ValType lhs, ValType rhs>
    struct add
    {
    	static const ValType value = lhs + rhs;
    };
    
    template<typename ValType, ValType lhs, ValType rhs>
    struct sub
    {
    	static const ValType value = lhs - rhs;
    };
    
    int main()
    {
    	std::cout << calc<int, 0, add, 5, 6, 7>::value << '\n' //Should be 18
    		      << calc<int, 100, sub, 5, 2, 3>::value; //Should be 100 - 5 - 2 - 3 = 90
    	std::cin.get();
    }
    

    Jedenfalls bringt dieser Code VS2013 bei mir zum abrauchen (Server 2012 x64). Auf GCC 4.7.2 (x64, Debian-Wheezy x64) compiliert der Code problemlos und es kommt auch die erwartete Ausgabe.

    Kann mir jemand a) sagen, ob der Fehler bei mir im Programm liegt und GCC das nur zufaellig frisst oder ob wirklich VS2013 einen Compiler-Bug enthaelt und, falls es ein Compiler-Bug sein koennte, b) bestaetigen, dass das Problem auch auf anderen Maschinen besteht?

    Wenns ein Bug ist, wuerde ich ihn gerne reporten. Insofern sind auch verkuerzte Beispiele, die den Fehler reproduzieren, willkommen.



  • Ich hab es mal intern an das VC++ Team weitergeleitet...
    Nur mal zur Info: Kleines Code kannst Du auch hier testen:
    http://rise4fun.com/Vcpp

    Kann man Feedback nicht auch direkt über das Hilfe-Menü einreichen? Hab es noch nicht installiert... ich dachte aber da haben die was eingebaut...



  • Ja, man kann auch 🙂 oder 😞 mit einer entsprechenden Message zum VS-Team senden (das Ding zeigt in der Titelleiste wirklich die Smileys an oO). Im Hilfe-Menue gibt's sicher auch was, hab noch nicht geguckt. EDIT: Ja da gibt's was zum Bug reporten, aber s.u.
    Ich wollte nur sicher gehen, dass nicht ich der bin, der Scheisse gebaut hat, da ich ein absoluter Newbie in Sachen TMP bin.



  • Wie es scheint, kann Visual C++ in partiellen Spezialisierung Nicht-Packs nicht mit Paramterpacks in Übereinstimmung bringen. Das macht es weitgehend unmöglich, solche Paramterpacks für TMP einzusehen (es sei denn, man nutzt eine "nicht-rekursiven" Ansatz, wie er vor einiger Zeit hier diskutiert wurde, wobei ich bezweifle, dass der Compiler dafür robust genug ist).

    Beispiel:

    template <int... i> struct foo;
    template <int a> struct foo<a>;
    

    --\testvc.cpp(2) : error C2753: 'foo<a>' : partial specialization cannot match argument list for primary template



  • @camper: Passiert selbiges bei Typ-Parametern?



  • Hier die Antwort vom MS STL Guru:

    This compiles cleanly and runs successfully with WCFB01's latest build, so it appears the compiler team fixed this after Preview.

    Sie wollen auch den neuesten Build auf http://rise4fun.com/Vcpp stellen... so kann man zumindest dort die Fortschritte sehen...



  • MS Durchschauer schrieb:

    @camper: Passiert selbiges bei Typ-Parametern?

    Nicht für diesen einfachen Fall, der Versuch den ursprünglichen Code entsprechend umzuschreiben

    #include <utility>
    
    template<typename ValType, ValType start, template <typename T, T, T> class Operator, typename... Args>
    struct calc_
    {
        static const ValType value = start;
    };
    
    template<typename ValType, ValType start, template <typename T, T, T> class Operator, typename current, typename... tail>
    struct calc_<ValType, start, Operator, current, tail...>
    {
        static const ValType value = Operator<ValType, calc_<ValType, start, Operator, tail...>::value, current::value>::value;
    };
    
    template<typename ValType, ValType start, template <typename T, T, T> class Operator, ValType ... args>
    struct calc : calc_<ValType, start, Operator, std::integral_constant<ValType, args>...> {};
    
    template<typename ValType, ValType lhs, ValType rhs>
    struct add
    {
        static const ValType value = lhs + rhs;
    };
    
    template<typename ValType, ValType lhs, ValType rhs>
    struct sub
    {
        static const ValType value = lhs - rhs;
    };
    
    #include <iostream> 
    int main()
    {
        std::cout << calc<int, 0, add, 5, 6, 7>::value << '\n' //Should be 18
                  << calc<int, 100, sub, 5, 2, 3>::value; //Should be 100 - 5 - 2 - 3 = 90
        std::cin.get();
    }
    

    führt trotzdem zu einem ICE



  • Naja, soetwas brauche ich zum Glück im Moment oder auch in fernerer oder fast schon fernster Zukunft nicht, puh, vor allem nicht mit integralen Konstanten, hab ja auch noch einen Taschenrechner oder ein CAS da. Irgendwann werden sie bestimmt schon einen Patch nachschieben.



  • Mit ein bisschen weiterer Spielerei erhalte ich

    #include <utility>
    
    template <typename T, typename U> struct add;
    template <typename T, T a, T b> struct add<std::integral_constant<T,a>,std::integral_constant<T,b>> : std::integral_constant<T,a+b> {};
    
    template <typename T, typename...> struct accumulate : T {};
    template <typename T, typename U, typename... V> struct accumulate<T, U, V...> : accumulate<typename add<T,U>::type, V...> {};
    
    template <typename T, T... i> struct accumulate_ : accumulate<std::integral_constant<T, i>...> {};
    #include <iostream>
    
    int main()
    {
      std::cout << accumulate<std::integral_constant<int, 1>>::value << '\n';
      std::cout << accumulate<std::integral_constant<int, 1>, std::integral_constant<int,2>>::value << '\n';
    //  std::cout << accumulate_<int, 1, 2>::value << '\n';
    }
    

    kein ICE mehr. Direkte Probleme bereiten also offenbar Paramterpacks aus non-type-Templateargumenten.


Anmelden zum Antworten