c++ - 用 constexpr 模拟 sizeof 的特殊属性

标签 c++

在 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))。但是,我在这里要问的是一种在我自己的代码中模拟该行为而不必满足于解决方法的方法。我怎样才能编写一个看起来和感觉起来像 sizeof,但又像 traits 一样特化的 bitsof?我是否必须接受 sizeof 有点特殊并接受它?

我最初有几个想法:

  1. 也许 decltype 的工作方式类似于 sizeof,例如decltype(0)decltype(int) 是同义词。不过运气不好。
  2. 也许我们可以用指针/引用模板参数做点什么。不过,我看不出有什么方法可以让推论在这种情况下正常工作,而且它会对我们可以使用 bitsof 的变量施加额外的限制。
  3. 也许是一些结合了模板和宏的疯狂 SFINAE,但我看不出实现它的方法,它总是只是一个语法错误。
  4. 可能会使用 GCC 的 statement-expr 扩展解决上述问题之一的限制。

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

最佳答案

你可以这样做:

#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))。在这里,我们在右侧使用重载的一元 +,然后使用重载的转换运算符,然后在左侧使用重载的二元 +。

关于c++ - 用 constexpr 模拟 sizeof 的特殊属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55131357/

相关文章:

c++ - 使用 g++ 连接两个具有相同函数签名的强函数符号的结果,为什么?

c++ - 如何打印 Linux 下 C++ 程序中调用的函数?

c++ - 内存使用问题

c++ - 如果索引表示为 x y 位置,则检查哪些 2d 数组元素彼此更接近

c++ - 隐式转换 CString 为 char*

c++ - 生命游戏,C++ - 多态数组(也许还有指针)

c++ - 为什么 std::is_invocable 不接受非类型模板参数

c# - 从 C++ 调用 C# 函数是否创建编译代码

c++ - 单个进程出错后如何正确退出 MPI 应用程序

c++ - 如何对调试器隐藏变量/函数名称?