我有一个简单而又令人生畏的问题,我自己无法解决。我有类似
的东西template<class T, class... Args>
T* create(SomeCastableType* args, size_t numArgs)
{
return new T(static_cast<Args>(args[INDEX_OF_EXPANSION])...);
}
假设SomeCastableType
可以转换为任何类型。显然我无法得到的是INDEX_OF_EXPANSION
。
非常感谢你的帮助。
答案 0 :(得分:21)
Indices trick,yay~
template<class T, class... Args, std::size_t... Is>
T* create(U* p, indices<Is...>){
return new T(static_cast<Args>(p[Is])...);
}
template<class T, class... Args>
T* create(U* p, std::size_t num_args){
assert(num_args == sizeof...(Args));
return create<T, Args...>(p, build_indices<sizeof...(Args)>{});
}
当然,我强烈建议使用smart pointer和std::vector
而不是原始指针。
答案 1 :(得分:3)
你需要一个帮手:
#include <tuple>
template <typename T, bool, typename Tuple, unsigned int ...I>
struct helper
{
static T * go(S * args)
{
return helper<T, sizeof...(I) + 1 == std::tuple_size<Tuple>::value,
Tuple, I..., sizeof...(I)>::go(args);
}
};
template <typename T, typename ...Args, unsigned int ...I>
struct helper<T, true, std::tuple<Args...>, I...>
{
static T * go(S * args)
{
return new T(static_cast<Args>(args[I])...);
}
};
template <typename T, typename ...Args>
T * create(S * args)
{
return helper<T, sizeof...(Args) == 0, std::tuple<Args...>>::go(args);
}
编辑:经过测试,似乎有效。
答案 2 :(得分:2)
假设
SomeCastableType
可转换为任何类型。显然我无法得到的是INDEX_OF_EXPANSION
。
自 C ++ 14 起,您就可以使用std::make_index_sequence
帮助程序来完成索引技巧 @Xeo提到的with the support from the standard library。 :
template<class T, class... Args, std::size_t... Is>
T* create(SomeCastableType* p, std::index_sequence<Is...>)
{
return new T(static_cast<Args>(p[Is])...);
}
template<class T, class... Args>
T* create(SomeCastableType* p, std::size_t num_args)
{
return create<T, Args...>(p, std::make_index_sequence<sizeof...(Args)>());
}
答案 3 :(得分:1)
如果使用c ++ 17的constexpr,我们可以获得索引查找功能的更具可读性/可理解性的实现(在这里我从未设法绕过其他答案):
template<typename Target, typename ListHead, typename... ListTails>
constexpr size_t getTypeIndexInTemplateList()
{
if constexpr (std::is_same<Target, ListHead>::value)
return 0;
else
return 1 + getTypeIndexInTemplateList<Target, ListTails...>();
}
可以如下使用:
size_t index = getTypeIndexInTemplateList<X, Foo,Bar,X,Baz>(); // this will return 2
或者,如果您具有可变模板化类型,并且想要在其中获取索引:
template<typename... Types>
class Container
{
public:
size_t getIndexOfType<typename T>() { return getTypeIndexInTemplateList<T, Types...>(); }
};
...
Container<Foo, Bar, X, Baz> container;
size_t container.getIndexOfType<X>(); // will return 2
它的工作方式是从列表中递归消除类型。因此,第一个示例的呼叫顺序基本上是:
getTypeIndexInTemplateList<X, Foo, Bar,X,Baz>() // ListHead = Foo, ListTails = Bar,X,Baz
getTypeIndexInTemplateList<X, Bar, X,Baz>() // ListHead = Bar, ListTails = X, Baz
getTypeIndexInTemplateList<X, X, Baz>() // ListHead = X, so now we return. Recursive addition takes care of calculating the correct index
该函数是constexpr,因此将全部在编译时执行,在运行时只是一个常量。
如果您请求列表中不存在的类型,则它将生成编译错误,因为它将尝试使用太少的模板参数来调用该函数。当然,如果该类型存在多次,则只会返回该类型的第一个实例的索引。