【问题标题】:Select every even (or odd) argument in template parameter pack选择模板参数包中的每个偶数(或奇数)参数
【发布时间】:2011-09-22 11:07:21
【问题描述】:

我想允许使用我正在编写的类来指定作为模板参数的类型列表以及这些类型的分配器列表,其中类型位于奇数位置而分配器位于偶数位置:

template<typename... T>
class MyClass {
  // Stuff inside
}

int main() {
  MyClass<SomeType1, AllocatorOfSomeType1> c1;
  MyClass<SomeType1, AllocatorOfSomeType1, 
          SomeType2, AllocatorOfSomeType2> c2;
  MyClass<SomeType1, AllocatorOfSomeType1, 
          SomeType2, AllocatorOfSomeType2,
          SomeType3, AllocatorOfSomeType3> c3;
  // And so on....
}

在内部,有一个类型的向量元组用于存储是有意义的:

std::tuple<std::vector<EveryOddTypeInParameterPack>...> m_storage_;

还有一个分配器元组供使用:

std::tuple<std::vector<EveryEvenTypeInParameterPack>...> m_storage_;

如何在代码中实际声明这些元组?理论上,我需要以某种方式选择参数包中的每个奇数/偶数类型 - 这可能吗?

【问题讨论】:

  • @Alf 你能详细说明一下整个“为什么”吗?如果你问我为什么要这个接口——因为我需要为这个类的用户提供一种方便的方法来指定分配器。我对(合理的)替代方案持开放态度。
  • 你可以只使用分配器作为你的模板参数列表,并使用 allocator::value_type 作为类型...
  • 我很想尝试类似旧的isEven(n) { return isOdd(n-1); } 例程...也许see this answer 将参数打包到一个元组中以进行传输。
  • @Kerrek:要使用它,您还需要一个isOdd(n) { return isEven(n - 1); },对吧? :-)
  • @James:是的,那是“读者练习”部分 :-)

标签: c++ templates c++11 metaprogramming


【解决方案1】:

虽然代码有点长,但我想机制没有 不必要的特殊性。
如果我正确理解了这个问题, 可能以下代码将达到目的:

// push front for tuple
template< class, class > struct PFT;

template< class A, class... T > struct PFT< A, tuple< T... > > {
  typedef tuple< A, T... > type;
};

// for even
template< class... > struct even_tuple;

template< class A, class B > struct even_tuple< A, B > {
  typedef tuple< A > type;
};
template< class A, class B, class... T > struct even_tuple< A, B, T... > {
  typedef typename PFT< A, typename even_tuple< T... >::type >::type type;
};
// As for odd elements, in the same way as even(please see the test on ideone)

// objective type
template< class > struct storage_type;

template< class... T > struct storage_type< tuple< T... > > {
  typedef tuple< vector< T >... > type;
};

template< class... T >
struct MyClass {
  typename storage_type< typename even_tuple< T... >::type >::type
    m_storage_even_;
  typename storage_type< typename  odd_tuple< T... >::type >::type
    m_storage_odd_;
};

这是对ideone 的测试。

【讨论】:

  • 哦,一点也不。很高兴它有帮助:-)
【解决方案2】:

大概是这样的:

#include <tuple>

// Example receptacle    
template <typename ...Args> struct MyContainer;

// Tuple concatenator
template<typename PackR, typename PackL> struct cat;
template<typename ...R, typename ...L>
struct cat<std::tuple<R...>, std::tuple<L...>>
{
  typedef std::tuple<R..., L...> type;
};

// Even/Odd extractors
template <typename ...Args> struct GetEven;
template <typename ...Args> struct GetOdd;

template <typename E1, typename O1, typename ...Args>
struct GetEven<E1, O1, Args...>
{
  typedef typename cat<std::tuple<E1>, typename GetEven<Args...>::value>::type value;
};
template <typename E1, typename O1>
struct GetEven<E1, O1>
{
  typedef std::tuple<E1> value;
};

template <typename E1, typename O1, typename ...Args>
struct GetOdd<E1, O1, Args...>
{
  typedef typename cat<std::tuple<O1>, typename GetEven<Args...>::value>::type value;
};
template <typename E1, typename O1>
struct GetOdd<E1, O1>
{
  typedef std::tuple<O1> value;
};

// Tuple-to-Receptacle mover
template <typename Pack, template <typename ...T> class Receiver> struct Unpack;
template <typename ...Args, template <typename ...T> class Receiver>
struct Unpack<std::tuple<Args...>, Receiver>
{
  typedef Receiver<Args...> type;
};

// Example consumer
template <typename ...Args>
struct Foo
{
  typedef typename Unpack<typename GetEven<Args...>::value, MyContainer>::type EvenVector;
  typedef typename Unpack<typename GetOdd<Args...>::value, MyContainer>::type OddVector;

  EvenVector x;
  OddVector y;
};

您仍然需要定义您的 MyContainer 类来使用可变参数做一些有用的事情,例如实现你的向量元组......(为什么不是元组向量呢?)

感谢brunocodutra 的元组技巧。

【讨论】:

  • 这“几乎”有效。这种方法的问题是 GetEven 和 GetOdd 的一般情况声明了一个类型的元组和一个元组。这可以通过使用您链接到的问题中的 cat 轻松解决。我会尽快接受这个答案。附言我实际上可以在这里粘贴我的固定代码,但你应该得到回答的功劳。
  • @Bartłomiej:你能解释一下你需要连接什么吗?我以为你想把偶数和赔率分开?我不介意你接受谁,但我很乐意根据你的需要修改答案。
  • 我的意思是当前状态下的代码不能按预期工作。如果你声明 Foo 那么 GetEven::value 将解析为 std::tuple>>。您想要/需要的是 std::tuple ,这是您需要其他答案中的 Cat 模板的地方。
  • @Bartłomiej:哦,是的,确实如此。干杯。不过,您已经得到了答案,所以下次我会记住这一点。
【解决方案3】:

这只是一个尝试

template<typename... T> class Myclass;

template<typename T1, typename allocT1>
class MyClass <T1, allocT1> {
  std::pair<T1, allocT1> myFirstArglist;
//and you have to do a check that allocT1::value_type is same as T1 or not
//or may be alloT1 is an allocator type or not(i'm thinking concepts, may be)
//this idea is inspired from Chris's comment
};

template<typename T1, typename allocT1, typename... T>
class Myclass<T1, allocT1, T...> {
std::pair<T1, allocT1> myFirstArglist;
Myclass<T>; //something like this
};

template<>
class Myclass<> {
//probably you would like some error message here
//when there are no types and containers
};

可能是我不够清楚,您可能想阅读 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2080.pdf

还有一篇与分配器类型设计相关的好帖子……你想看看: C++ Design Pattern for allocator type arguments

【讨论】:

  • 专业化语法必须是:MyClass&lt;T1, allocT1&gt;MyClass&lt;T1, allocT1, T...&gt;,并且不要忘记将基本模板声明粘贴在某处。
【解决方案4】:

我知道您的问题最初被标记为“c++11”,但我认为值得为后代指出的是,在 C++14 中您可以访问 make_index_sequence,这使得整个事情变得非常简单。为了过滤一个元组,我会从这个大纲开始:https://quuxplusone.github.io/blog/2018/07/23/metafilter/

然后我们会得到这样的结果 (Godbolt):

template<bool> struct zero_or_one {
    template<class E> using type = std::tuple<E>;
};

template<> struct zero_or_one<false> {
    template<class E> using type = std::tuple<>;
};

template<class Tuple, class = std::make_index_sequence<std::tuple_size<Tuple>::value>>
struct just_evens;

template<class... Es, size_t... Is>
struct just_evens<std::tuple<Es...>, std::index_sequence<Is...>> {
    using type = decltype(std::tuple_cat(
        std::declval<typename zero_or_one<Is % 2 == 0>::template type<Es>>()...
    ));
};

要获得just_odds,您需要将条件从Is % 2 == 0 切换到Is % 2 != 0

示例用法:

static_assert(std::is_same<
    just_evens<std::tuple<char, short, int, long, double>>::type,
    std::tuple<char, int, double>
>::value, "");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-15
    • 2021-02-11
    • 1970-01-01
    • 2019-10-08
    • 2022-01-08
    • 2019-11-22
    • 2021-10-18
    相关资源
    最近更新 更多