使用 constexpr 模拟 sizeof 的特殊属性

2023-12-25

In C++ sizeof有点独特,因为这样写是合法的:

int x;
sizeof(x); // a variable

也简单地说:

sizeof(int); // a type

(不过,我现在宁愿忽略第三个更奇怪的变体,不需要括号,因为我很确定这是不可能模仿的)

我希望自己能够复制这种行为。为了激励它,我有一个例子bitsof操作员。

#include <climits>

template <typename T>
struct bits_traits {
  enum { value = sizeof(T) * CHAR_BIT };
};

struct int_12_bit {
  enum { bits = 12 };
  // Let's pretent this has a bunch of code for looking and feeling like a 12bit int in a helpful and portable way
};

template <>
struct bits_traits<int_12_bit> {
  enum { value = int_12_bit::bits };
};

#define bitsof(x) bits_traits<x>::value

int main() {
  using std::size_t;
  size_t b = bitsof(int);
  size_t a = bitsof(int_12_bit);

  int_12_bit x;
  size_t c = bitsof(x); // <-- Not cool
}

显然,我可以使用 sizeof 以宏的形式编写整个内容,例如

#define bitsof(x) (sizeof(x) * CHAR_BIT)

但后来我就失去了“专业化”它的能力。

同样我可以写size_t c = bitsof(decltype(x))。然而,我在这里要求的是一种在我自己的代码中模拟该行为的方法,而不必解决解决方法。我怎样才能写一个bitsof看起来和感觉起来都像sizeof,但是像特质一样专业?我必须接受吗sizeof是不是有点特别并忍受它?

我最初有一些想法:

  1. Perhaps decltype作品就像sizeof, e.g. decltype(0) and decltype(int)是同义的。但那里没有运气。
  2. 也许我们可以用指针/引用模板参数做一些事情。不过,我看不到一种方法可以让推论在这种情况下正常工作,并且这会对我们可以使用哪些变量施加额外的限制bitsof with.
  3. 也许是一些疯狂的 SFINAE 结合了模板和宏,但我看不到实现这种情况的方法,它总是只是一个语法错误。
  4. 可能可以使用 GCC 的语句表达式扩展来解决上述问题之一的局限性。

因为有一个简单的解决方法decltype更多的是一个学习实验,我愿意接受使用任何 C++ 发布的编译器中可用的任何东西来针对任何过去、现在或未来标准的想法。


你可以这样做:

#include <type_traits>

#define bitsof(k) decltype(bitsof_left+(k)+bitsof_right)

template <class K>
struct bits_traits { /* whatever you want here */ };

struct bitsof_left_t {
    template <class T>
    bits_traits<T> operator+(const T&);
} bitsof_left;

struct bitsof_right_t {
    template <class T>
    friend T operator+(const T&, bitsof_right_t);

    bitsof_right_t operator+();

    template <class T>
    operator T() const;

} bitsof_right;

int main()
{
    using foo = bitsof(42);
    using bar = bitsof(int);

    static_assert(std::is_same<foo, bits_traits<int>>::value);
    static_assert(std::is_same<bar, bits_traits<int>>::value);
}

它的工作原理是这样的。

a + (42) + b被解析为(a + (42)) + b),然后重载二进制文件operator+在我的示例中,运算符仅被声明,未定义,但由于它是未评估的上下文,因此并不重要。

a + (int) + b被解析为a + ((int) (+ b))。这里我们在右侧使用重载的一元 +,然后在左侧使用重载的强制转换运算符,然后在左侧使用重载的二进制 +。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 constexpr 模拟 sizeof 的特殊属性 的相关文章

随机推荐