【问题标题】:std::tuple_size and partially specialized templatesstd::tuple_size 和部分专用模板
【发布时间】:2014-03-01 14:51:49
【问题描述】:

这个小程序

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;
}

在 gcc 中编译良好,但在 MS Visual Studio 2013 中会产生“错误 C2755: 'MetaData::addVarDesc::value,MSGT>' : non-type parameter of a partial specialization must be a simple identifier”。

我想知道,此代码在 VS 2013 中工作所需的最小/最佳更改是什么。

编辑尝试换一种说法:如何将元组大小作为编译时常量,有资格用作模板参数?

编辑基本上,使用integral_costant&lt;int, ID&gt; 而不是int ID 解决了这个问题。

【问题讨论】:

  • 此代码格式不正确,请参阅 open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1315 。您需要将ID 设置为类型参数,并将std::tuple_size&lt;...&gt;::value 包装在int_&lt;...&gt;std::integral_constant&lt;int, ...&gt; 中。见stackoverflow.com/questions/5978617/…
  • 好吧,gcc 不介意,考虑到它在标准合规性方面通常比微软的要好,我认为可能没有标准限制。你能写一个答案,以便我可以将问题标记为已解决吗?

标签: c++ templates visual-c++ c++11 variadic-templates


【解决方案1】:

我被要求创建一个答案。您需要将数字包装在类型中

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

    }
};

【讨论】:

    【解决方案2】:

    虽然此代码不符合标准,但您可以很简单地对其进行更改。这是MetaData类的修改版本:

    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;
        }
    };
    

    这个问题也可以用另一种方式解决——使用MetaData::addVarDesc::exec方法的包装器:

    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;
        }
    };
    

    如果这种延迟顺序(从最后一个到第一个元组元素)不适合您,这两种方法都可能是错误的。但可以对其进行修改以解决此问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-21
      • 1970-01-01
      • 2021-04-18
      • 1970-01-01
      相关资源
      最近更新 更多