Reputation: 544
this small program
#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.
Upvotes: 2
Views: 516
Reputation: 507005
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)
{
}
};
Upvotes: 2
Reputation: 7473
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.
Upvotes: 2