我正在尝试使用C++模板元编程来尝试创建具有以下语义的存储类:它采用任意数量的类型,并使用公共(public)访问接口(interface)为每种类型存储用户定义类型的容器。我可以使用以下代码来实现它,该代码使用来自decltype扩展列表的多重继承(A
和B
只是要放入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功能? 最佳答案
这在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
。通过使用
StorageBase
和decltype
来完成肮脏的工作,可以简化表达式。关于c++ - 可变参数模板中扩展decltype的继承,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48554485/