我正在尝试使用C++模板元编程来尝试创建具有以下语义的存储类:它采用任意数量的类型,并使用公共(public)访问接口(interface)为每种类型存储用户定义类型的容器。我可以使用以下代码来实现它,该代码使用来自decltype扩展列表的多重继承(AB只是要放入Storage的虚拟结构):

#include <iostream>
#include <string>
#include <map>
#include <unordered_map>

struct A
{
  int v = -1;
};

struct B
{
  std::string v;
};

typedef int Key;

template<typename T>
auto componentContainer();

template<>
auto componentContainer<A>()
{
    return std::unordered_map<Key, A>();
}

template<>
auto componentContainer<B>()
{
    return std::map<Key, B>();
}

template<typename... Component>
struct Storage : public decltype(componentContainer<Component>())...
{
    template <typename T>
    using Container = decltype(componentContainer<T>());

    template<typename T>
    T& get(int index)
    {
       return Container<T>::operator [](index);
    }

    template<typename T>
    const T& get(int index) const
    {
        return Container<T>::operator [](index);
    }

    template<typename T>
    void put(int index, const T& v)
    {
       Container<T>::operator [](index) = v;
    }

    template<typename T, typename F>
    void apply(F f)
    {
        for (auto p = Container<T>::begin();
             p != Container<T>::end();
             p++)
        {
            f(p);
        }
    }
};

int main(int argc, char** argv)
{
    Storage<A,B> s;
    s.put<A>(0,  {12});
    s.put<A>(3,  {42});
    s.put<B>(0, {"melta"});
    s.put<B>(42, {"multimelta"});

    auto printer = [](auto p) { std::cout <<p->first <<": " << p->second.v <<std::endl;};
    s.apply<A>(printer);
    s.apply<B>(printer);

   return 0;
}

此代码在gcc 5.1.0中可以正常编译并产生预期的结果,但在Visual Studio 2015中编译失败,并显示以下错误消息:
main.cpp(37): error C2143: syntax error: missing ',' before '...'
main.cpp(70): note: see reference to class template instantiation 'Storage<Component...>' being compiled
main.cpp(37): error C3520: 'Component': parameter pack must be expanded in this context
main.cpp(74): note: see reference to class template instantiation 'Storage<A,B>' being compiled
main.cpp(37): error C3770: 'unknown-type': is not a valid base class

问题是,我不确定从这样的扩展decltype列表继承是否合法(即符合标准)。因此,我的问题是:
  • struct Storage: public decltype(componentContainer<Component>())...在标准C++中是合法的东西还是gcc功能?
  • 如果可以,可以在Visual Studio中完成吗?
  • 最佳答案

    这在MSVC中对我有用。

    template<typename T>
    struct StorageBase
    {
        using Type = decltype(componentContainer<T>());
    };
    
    template<typename... Component>
    struct Storage : public StorageBase<Component>::Type...
    { }
    

    语法错误使我相信编译器在扩展参数包之前尝试评估decltype表达式-因此为什么它也会发出'Component': parameter pack must be expanded in this context

    通过使用StorageBasedecltype来完成肮脏的工作,可以简化表达式。

    关于c++ - 可变参数模板中扩展decltype的继承,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48554485/

    10-13 06:21