【问题标题】:Count non-default template arguments with metaprogramming?使用元编程计算非默认模板参数?
【发布时间】:2013-02-04 09:30:48
【问题描述】:

我有一个接受 1 到 8 个整数参数的模板类。每个参数的允许范围是 0..15。每个参数的默认值 16 允许我检测未使用的参数。

我想将用户提供的参数数量作为编译时常量。我可以使用模板助手类和许多部分专业化来做到这一点。

我的问题是,我可以使用一些递归元编程来清理它吗?我有什么作品,但感觉在语法上可以改进。

很遗憾,我无法使用可变参数模板和任何其他 c++0x。

#include <stdint.h>
#include <iostream>

template<uint8_t p0,uint8_t p1,uint8_t p2,uint8_t p3,uint8_t p4,uint8_t p5,uint8_t p6,uint8_t p7>
struct Counter { enum { COUNT=8 }; };

template<uint8_t p0,uint8_t p1,uint8_t p2,uint8_t p3,uint8_t p4,uint8_t p5,uint8_t p6>
struct Counter<p0,p1,p2,p3,p4,p5,p6,16> { enum { COUNT=7 }; };

template<uint8_t p0,uint8_t p1,uint8_t p2,uint8_t p3,uint8_t p4,uint8_t p5>
struct Counter<p0,p1,p2,p3,p4,p5,16,16> { enum { COUNT=6 }; };

template<uint8_t p0,uint8_t p1,uint8_t p2,uint8_t p3,uint8_t p4>
struct Counter<p0,p1,p2,p3,p4,16,16,16> { enum { COUNT=5 }; };

template<uint8_t p0,uint8_t p1,uint8_t p2,uint8_t p3>
struct Counter<p0,p1,p2,p3,16,16,16,16> { enum { COUNT=4 }; };

template<uint8_t p0,uint8_t p1,uint8_t p2>
struct Counter<p0,p1,p2,16,16,16,16,16> { enum { COUNT=3 }; };

template<uint8_t p0,uint8_t p1>
struct Counter<p0,p1,16,16,16,16,16,16> { enum { COUNT=2 }; };

template<uint8_t p0>
struct Counter<p0,16,16,16,16,16,16,16> { enum { COUNT=1 }; };


template<uint8_t p0,uint8_t p1=16,uint8_t p2=16,uint8_t p3=16,
         uint8_t p4=16,uint8_t p5=16,uint8_t p6=16,uint8_t p7=16>
struct MyClass {

  void printArgCount() {
    std::cout << Counter<p0,p1,p2,p3,p4,p5,p6,p7>::COUNT << std::endl;
  }
};


main() {
  MyClass<4,7,8,12,15,1> foo;

  foo.printArgCount();
}

【问题讨论】:

  • 我觉得不错。我怀疑是否有更好的解决方案。
  • 我不认为 Boost 的可变参数模板是获取用户想要传递的参数的选项?
  • 我注意到我的解决方案和 Crog 的解决方案之间的行为差​​异:他计算所有非 16 参数,我数到第一个参数,即 16。目前,我认为我们可能都错了事实上,我们应该数到不是 16 的最新参数……这对你有影响吗?
  • (p1 != 16) + (p2 != 16) +... 有什么问题?
  • @Matthieu:不,没关系,它们都为我工作。用户在列表中的任何位置提供 16 是不合法的,因此计数到前 16 或所有非 16 都可以正常工作。

标签: c++ templates metaprogramming c++03


【解决方案1】:

为什么不只检查出现的第一个16

template <uint8_t p0, ...>
struct Counter {
    enum { COUNT = (p1 == 16 ? 1 : 
                    p2 == 16 ? 2 :
                    p3 == 16 ? 3 :
                    p4 == 16 ? 4 :
                    p5 == 16 ? 5 :
                    p6 == 16 ? 6 :
                    p7 == 16 ? 7 :
                               8
                   ) };
};

【讨论】:

  • 确实非常整洁。我不知道你可以在枚举声明中做这种逻辑。
  • @AndyBrown:您可以将大多数(全部?)内置函数用于常量表达式(enumstatic &lt;built-in&gt; const 内联定义、模板非类型参数,...)。例如sizeof 也是游戏。
【解决方案2】:

你可以这样做,但它仍然不如其他一些使用 c++11 提供的解决方案漂亮/好:

template< uint8_t p0 = 16,uint8_t p1 = 16,uint8_t p2 = 16,uint8_t p3 = 16,uint8_t p4 = 16,uint8_t p5 = 16,uint8_t p6 = 16,uint8_t p7 = 16>
struct Counter 
{ 
    enum { COUNT= int(p0!=16) + int(p1!=16) + int(p2!=16) + int(p3!=16) + int(p4!=16) + int(p5!=16) + int(p6!=16) + int(p7!=16) }; 

    int count() const
    { return  COUNT; }
};

【讨论】:

  • 默认模板参数不是 C++11 的一部分吗?
  • 不,据我所知,类的默认模板参数已经存在很长时间了,因为我一直使用它们。有人可能确切地知道他们何时出现
  • @chris: functions 的默认参数是 C++11 的一部分。
【解决方案3】:

您可以递归设置计数器,如下所示:

template<typename>
struct Counter;

template<>
struct Counter<> { static const int COUNT = 0;};

template<typename T, typename... Args>
struct count<T, Args...> //partial specialization
{ static const int value = 1 + count<Args...>::COUNT;};

【讨论】:

  • 您可能错过了更改,但没有 C++11。
猜你喜欢
  • 2012-01-25
  • 2017-09-16
  • 1970-01-01
  • 2011-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-28
  • 1970-01-01
相关资源
最近更新 更多