20

我有一个简单但令人生畏的问题,我自己无法解决。我有类似的东西

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

非常感谢您的帮助。

4

4 回答 4

22

指数把戏,耶~

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

当然,我强烈建议使用智能指针和 astd::vector而不是原始指针。

于 2013-02-22T00:02:45.357 回答
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);
}

编辑:经过测试,似乎有效。

于 2013-02-21T23:23:06.110 回答
3

使用 c++17 的 constexpr if,我们可以获得索引查找函数的更易读/更易理解的实现(我从来没有设法理解这里的其他答案):

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,所以这将在编译时执行,它在运行时只是一个常量。

如果您请求列表中不存在的类型,它将产生编译错误,因为它会尝试使用太少的模板参数调用函数。当然,如果该类型不止一次出现,这只会返回列表中该类型的第一个实例的索引。

于 2020-03-25T17:58:00.250 回答
2

假设SomeCastableType可以转换为任何类型。显然我无法得到的是INDEX_OF_EXPANSION

C++14开始,您可以使用帮助程序在标准库的支持下执行@Xeo 提到的索引技巧,如下所示:std::make_index_sequence

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)>());
}
于 2019-04-23T08:54:26.487 回答