문제

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.

도움이 되었습니까?

해결책

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)
    {

    }
};

다른 팁

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.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top