类型在可变参数模板参数包中的位置

发布于 2024-11-07 14:32:22 字数 421 浏览 3 评论 0原文

我正在尝试 C++0x,我想知道如何解决出现的以下问题。 我有一个可变参数模板类:

template<typename... T>
class MyLovelyClass {

 template<typename SomeType>
 void DoSthWithStorageOfSomeType();

 private:
  std::tuple<std::vector<T>...> m_storage;
};

该函数应该对 m_storage 元组中对应于 SomeType 模板参数的向量进行某种操作(如果不这样做,则编译时失败)。 怎样才能做到这一点呢?

我的想法是在参数包中找到 SomeType 的索引,然后使用 std::get 获取适当的向量,但我不知道如何执行第一部分。

I'm giving C++0x a try and I was wondering how to solve the following problem that came up.
I've got a variadic template class:

template<typename... T>
class MyLovelyClass {

 template<typename SomeType>
 void DoSthWithStorageOfSomeType();

 private:
  std::tuple<std::vector<T>...> m_storage;
};

The function there is suppose to do some sort of manipulation on the vector in m_storage tuple that corresponds to the SomeType template argument (or compile time fail if it doesn't).
How one can do this?

My idea was to find the index of SomeType in parameter pack and then use std::get to obtain the appropriate vector, but I don't know how to to do the first part.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

荆棘i 2024-11-14 14:32:22

下面是一些代码,用于对元组中找到的第一个类型 U 进行线性搜索,如果找不到 U,则会给出编译时错误。请注意,如果元组包含多个 U,则它只会找到第一个。不确定这是否是您想要的政策。它将编译时索引返回到第一个 U 的元组中。也许您可以将其用作 std::get 的索引。

免责声明:为这个答案而拼凑在一起。仅进行了轻微测试。诸如空元组之类的边缘情况会出现令人讨厌的错误消息,但可以改进。 ETC。

#include <type_traits>
#include <tuple>

template <class Tuple, class T, std::size_t Index = 0>
struct find_first;

template <std::size_t Index, bool Valid>
struct find_first_final_test
    : public std::integral_constant<std::size_t, Index>
{
};

template <std::size_t Index>
struct find_first_final_test<Index, false>
{
    static_assert(Index == -1, "Type not found in find_first");
};

template <class Head, class T, std::size_t Index>
struct find_first<std::tuple<Head>, T, Index>
    : public find_first_final_test<Index, std::is_same<Head, T>::value>
{
};

template <class Head, class ...Rest, class T, std::size_t Index>
struct find_first<std::tuple<Head, Rest...>, T, Index>
    : public std::conditional<std::is_same<Head, T>::value,
                    std::integral_constant<std::size_t, Index>,
                    find_first<std::tuple<Rest...>, T, Index+1>>::type
{
};

#include <iostream>

int main()
{
    typedef std::tuple<char, int, short> T;
    std::cout << find_first<T, double>::value << '\n';
}

Here's some code to do a linear search of a tuple for the first type U it finds, and gives a compile-time error if it can't find U. Note if the tuple contains multiple U's it only finds the first one. Not sure if that is the policy you want or not. It returns the compile-time index into the tuple of the first U. Perhaps you could use it as the index into your std::get.

Disclaimer: Thrown together for this answer. Only lightly tested. Edge cases such as an empty tuple have a nasty error message that could be improved. etc.

#include <type_traits>
#include <tuple>

template <class Tuple, class T, std::size_t Index = 0>
struct find_first;

template <std::size_t Index, bool Valid>
struct find_first_final_test
    : public std::integral_constant<std::size_t, Index>
{
};

template <std::size_t Index>
struct find_first_final_test<Index, false>
{
    static_assert(Index == -1, "Type not found in find_first");
};

template <class Head, class T, std::size_t Index>
struct find_first<std::tuple<Head>, T, Index>
    : public find_first_final_test<Index, std::is_same<Head, T>::value>
{
};

template <class Head, class ...Rest, class T, std::size_t Index>
struct find_first<std::tuple<Head, Rest...>, T, Index>
    : public std::conditional<std::is_same<Head, T>::value,
                    std::integral_constant<std::size_t, Index>,
                    find_first<std::tuple<Rest...>, T, Index+1>>::type
{
};

#include <iostream>

int main()
{
    typedef std::tuple<char, int, short> T;
    std::cout << find_first<T, double>::value << '\n';
}
千秋岁 2024-11-14 14:32:22

C++14 解决方案:

template <typename T, typename U=void, typename... Types>
constexpr size_t index() {
    return std::is_same<T, U>::value ? 0 : 1 + index<T, Types...>();
}

使用:

cout << index<A, Args...>() << "\n";

C++14 solution:

template <typename T, typename U=void, typename... Types>
constexpr size_t index() {
    return std::is_same<T, U>::value ? 0 : 1 + index<T, Types...>();
}

Use:

cout << index<A, Args...>() << "\n";
花伊自在美 2024-11-14 14:32:22

我通过返回 SIZE_MAX 向 Elazar 的解决方案添加了对“未找到类型”情况的支持:

template <class T, class F = void, class ...R>
constexpr size_t TypeIndex() {
    return is_same<T,F>::value
         ? 0
         : is_same<F,void>::value || TypeIndex<T,R...>() == SIZE_MAX
         ? SIZE_MAX
         : TypeIndex<T,R...>() + 1;
}

编辑:我转而使用参数包的大小作为“未找到”索引值。这就像 STL 中“最后一次”索引或迭代器的用法,是一个更优雅的解决方案:

template <class T, class F = void, class ...R>
constexpr size_t TypeIndex() {
    return is_same<T,F>::value || is_same<F,void>::value ? 0 : TypeIndex<T,R...>() + 1;
}

I added support for the "type not found" case to Elazar's solution, by returning SIZE_MAX:

template <class T, class F = void, class ...R>
constexpr size_t TypeIndex() {
    return is_same<T,F>::value
         ? 0
         : is_same<F,void>::value || TypeIndex<T,R...>() == SIZE_MAX
         ? SIZE_MAX
         : TypeIndex<T,R...>() + 1;
}

EDIT: I switched to using the size of the parameter pack as the "not found" index value. This is like the STL usage of a "one past the end" index or iterator and makes a more elegant solution:

template <class T, class F = void, class ...R>
constexpr size_t TypeIndex() {
    return is_same<T,F>::value || is_same<F,void>::value ? 0 : TypeIndex<T,R...>() + 1;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文