推断声明的类型

Deduce the type of a declaration

我正在编写一个将声明作为其单个参数的宏。是否可以 推断宏内部声明 的类型而不将单个参数拆分为单独的 typeidentifier 参数?

#define M(declaration) \
    declaration;       \
    static_assert(sizeof(/* deduce type of 'declaration' */) == 4, "!")

M(int i);
M(double d{3.14});
M(std::string s{"Hello, world!"});

以下实现可行,但感觉不太用户友好 (imo):

#define M(type, identifier) \
    type identifier;        \
    static_assert(sizeof(type) == 4, "!")

M(int, i);
M(double, d{3.14});
M(std::string, s{"Hello, world!"});

如果可能的话,我更愿意将声明作为一个参数。


相关问题: Macro to get the type of an expression;但我没能在我的示例中使用该代码(编译器错误:expected nested-name-specifier)。

如果您的静态断言消息真的那么简单"!"1,我建议您放弃预处理器。让类型系统为你工作:

namespace detail {
  template<typename T>
  struct check_declared_type {
    using type = T;
    static_assert(sizeof(type) == 4, "!");
  };
}

template<typename T>
using M = typename detail::check_declared_type<T>::type;

// .. Later

int main() {
  M<int> i;
  M<double> d{3.14};
  M<std::string> s{"Hello, world!"};
}

1 - 具体来说,如果您不需要预处理器为您字符串化任何内容。

这个宏应该适用于您的所有示例,但它确实有一个严重的问题:

#define M(declaration) \
    declaration;       \
    do { \
        struct dummy__ { declaration; }; \
        static_assert(sizeof(dummy__) == 4, "!"); \
    } while (false)

问题是 class 定义中的初始化程序必须在顶层使用 = 标记或花括号初始化列表,而不是在顶层使用括号。因此,例如 M(SomeClass obj(true, 3)); 将无法编译,即使 sizeof(SomeClass)==4 也是如此。由于大括号初始化器并不完全等同于括号初始化器,这意味着某些声明将无法与宏一起使用。