Question

this small program

https://ideone.com/dqVJbN

#include <iostream>
#include <tuple>
#include <string>
using namespace std;

class MetaData
{
public:
    template<int ID, class T>
    void addVar(string varNames)
    {
        // do smth
    }

    template<int ID, class MSGT>
    struct addVarDesc
    {
        static void exec(MetaData& md, string varNames)
        {
            typedef typename std::tuple_element<ID, typename MSGT::values_type>::type varType;
            md.addVar<ID, varType>(varNames);
            addVarDesc<ID+1, MSGT>::exec(md, varNames);
        }
    };

    template<class MSGT>
    struct addVarDesc<std::tuple_size<typename MSGT::values_type>::value, MSGT>
    {
        static void exec(MetaData& md, string varNames)
        {

        }
    };

    template<class MSGT>
    static MetaData createMetaData(string varNames)
    {
        MetaData md;
        MetaData::addVarDesc<0, MSGT>::exec(md, varNames);
        return md;
    }
};

template<typename... Types>
class Message
{
public:
    tuple<Types...> m_values;
    typedef tuple<Types...> values_type;

    static MetaData m_meta;
};

typedef Message<string, double> MyMessageType;

template<>
MetaData MyMessageType::m_meta = MetaData::createMetaData<MyMessageType>("name\nmass");

int main() {
    // your code goes here
    return 0;
}

compiles well in gcc, yet produces an "error C2755: 'MetaData::addVarDesc::value,MSGT>' : non-type parameter of a partial specialization must be a simple identifier" in MS Visual Studio 2013.

I wonder, what is the smallest/best change required here for this code to work in VS 2013.

EDIT Trying to rephrase it differently: how can i get tuple size as compile-time constant, eligible to use as template parameter?

EDIT Basically, using integral_costant<int, ID> instead of int ID resolved the issue.

Was it helpful?

Solution

I have been asked to create an answer. You need to wrap the number in a type

template<typename ID, class MSGT>
struct addVarDescImpl;

template<int ID, class MSGT>
struct addVarDesc : addVarDescImpl<std::integral_constant<int, ID>, MSGT>
{};

template<typename ID, class MSGT>
struct addVarDescImpl
{
    static void exec(MetaData& md, string varNames)
    {
        typedef typename std::tuple_element<ID::value, typename MSGT::values_type>::type varType;
        md.addVar<ID::value, varType>(varNames);
        addVarDesc<ID::value+1, MSGT>::exec(md, varNames);
    }
};

template<class MSGT>
struct addVarDescImpl<
   std::integral_constant<int, std::tuple_size<typename MSGT::values_type>::value>,
   MSGT>
{
    static void exec(MetaData& md, string varNames)
    {

    }
};

OTHER TIPS

Although this code is not standard compliant, you can quite simply change it. Here is a modified version of MetaData class:

class MetaData
{
public:
    template<int ID, class T>
    void addVar(string varNames)
    {
        // do smth
    }

    template<class MSGT, int ID = std::tuple_size<typename MSGT::values_type>::value - 1>
    struct addVarDesc
    {
        static void exec(MetaData& md, string varNames)
        {
            typedef typename std::tuple_element<ID, typename MSGT::values_type>::type varType;
            md.addVar<ID, varType>(varNames);
            addVarDesc<MSGT, ID-1>::exec(md, varNames);
        }
    };

    template<class MSGT>
    struct addVarDesc<MSGT, 0>
    {
        static void exec(MetaData& md, string varNames)
        {

        }
    };

    template<class MSGT>
    static MetaData createMetaData(string varNames)
    {
        MetaData md;
        MetaData::addVarDesc<MSGT>::exec(md, varNames);
        return md;
    }
};

The problem can also be solved in another way - using a wrapper around MetaData::addVarDesc::exec method:

class MetaData
{
public:
    template<int ID, class T>
    void addVar(string varNames)
    {
        // do smth
    }

    template<int ID, class MSGT>
    struct addVarDescImpl
    {
        static void exec(MetaData& md, string varNames)
        {
            typedef typename std::tuple_element<ID, typename MSGT::values_type>::type varType;
            md.addVar<ID, varType>(varNames);
            addVarDescImpl<ID-1, MSGT>::exec(md, varNames);
        }
    };

    template<class MSGT>
    struct addVarDescImpl<0, MSGT>
    {
        static void exec(MetaData& md, string varNames)
        {

        }
    };

    template<class MSGT>
    static void addVarDesc(MetaData& md, string varNames)
    {
        addVarDescImpl<std::tuple_size<typename MSGT::values_type>::value - 1, MSGT>::exec(md, varNames);
    }

    template<class MSGT>
    static MetaData createMetaData(string varNames)
    {
        MetaData md;
        addVarDesc<MSGT>(md, varNames);
        return md;
    }
};

Both methods may be wrong if such back order (from last to first tuple element) is not suitable for you. But they can be modified to account for this.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top