Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MSVC2015 update 3 variadic template workaround

Visual Studio 2015 update 3 improved support of C++11 much, but I have strange problem and I am searching for workaround.

When compiling variadic-template code with MSVC for template type arguments ("fully defined types") all works good, but if I want to use template template arguments ("partially defined types"), the result becomes incorrect.

#include <iostream>
using namespace std;

template <template<typename> class... TS>
struct PARTIAL {
    static void test(std::ostream& out)
    {
        out << "PARTIAL-PROBLEM" << endl;
    }
};
template <template<typename> class T>
struct PARTIAL<T>{
    static void test(std::ostream& out)
    {out << "PARTIAL-OK-END" << endl;}
};
template <template<typename> class T, template<typename> class... TS>
struct PARTIAL<T, TS...>{
    static void test(std::ostream& out)
    {
        out << "PARTIAL-OK" << endl;
        PARTIAL<TS...>::test(out);
    }
};

template <class... TS>
struct FULL {
    static void test(std::ostream& out)
    {
        out << "FULL-PROBLEM" << endl;
    }
};
template <class T>
struct FULL<T>{
    static void test(std::ostream& out)
    {out << "FULL-OK-END" << endl;}
};
template <class T, class... TS>
struct FULL<T, TS...>{
    static void test(std::ostream& out)
    {
        out << "FULL-OK" << endl;
        FULL<TS...>::test(out);
    }
};
template <typename T>
struct B{};
int main()
{
    FULL<int, int, int>::test(cout);
    PARTIAL<B, B, B>::test(cout);
    return 0;
}

The output of GCC5.3 (MINGW):

FULL-OK
FULL-OK
FULL-OK-END
PARTIAL-OK
PARTIAL-OK
PARTIAL-OK-END

The output of MSVC:

FULL-OK
FULL-OK
FULL-OK-END
PARTIAL-OK
PARTIAL-OK
PARTIAL-OK
PARTIAL-PROBLEM

MSVC produces code different way for full defined types and partials. What should be the best workaround of this?

here is demo that works good on GCC

like image 823
Evgeniy Avatar asked Jun 21 '16 15:06

Evgeniy


1 Answers

Adding another parameter to the recursive case will ensure that it isn't selected for the terminating case:

template <template<typename> class T, template<typename> class T2, template<typename> class... TS>
//                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
struct PARTIAL<T, T2, TS...>{
//                ^^^^
    static void test(std::ostream& out)
    {
        out << "PARTIAL-OK" << endl;
        PARTIAL<T2, TS...>::test(out);
                ^^^^
    }
};
like image 93
ecatmur Avatar answered Oct 18 '22 14:10

ecatmur