【问题标题】:Position of a type in a variadic template parameter pack可变参数模板参数包中类型的位置
【发布时间】:2011-08-27 06:54:22
【问题描述】:

我正在尝试 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 获取适当的向量,但我不知道如何做第一部分。

【问题讨论】:

  • C++14,因此一些标准库实现提供std::get&lt;std::vector&lt;T&gt;&gt;(m_storage)。你应该检查一下你的是否有这个功能,让事情变得超级简单。

标签: c++11 metaprogramming variadic-templates


【解决方案1】:

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

免责声明:为这个答案一起抛出。只进行了轻微测试。诸如空元组之类的边缘情况有一个令人讨厌的错误消息,可以改进。等等

#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';
}

【讨论】:

  • 谢谢 - 我喜欢!我可以建议两件事吗:1)将 std::integral_constant<:size_t> 的继承添加到 false 案例中,以避免找不到 ::value 的额外错误。 2) 为空元组模板 struct find_first<:tuple>, T, Index> 添加一个特化: public find_first_final_test { };
  • 我希望您将使用此代码作为基础来构建您需要的内容,例如添加您的两个建议。带着它跑! :-)
【解决方案2】:

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";

【讨论】:

  • 是的,当类型不在列表中时,它会在 g++ 5.4 上出现段错误(尚未尝试 6)。
【解决方案3】:

我通过返回 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;
}

【讨论】:

    猜你喜欢
    • 2013-09-11
    • 1970-01-01
    • 2015-08-09
    • 1970-01-01
    • 2013-02-18
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    相关资源
    最近更新 更多