推断声明的类型

问题描述 投票:0回答:3

我正在编写一个宏,它将声明作为其单个参数。是否可以在宏内部推导声明的类型,而不将单个参数拆分为单独的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!"});

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


相关问题: 获取表达式类型的宏;但我未能让该代码在我的示例中工作(编译器错误:预期的嵌套名称说明符)。

c++ macros type-deduction
3个回答
2
投票

如果你的静态断言消息真的那么简单

"!"
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 - 具体来说,如果您不需要预处理器为您字符串化任何内容。


1
投票

这个宏应该适用于您的所有示例,但它确实有一个令人讨厌的问题:

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

问题是类定义中的初始化器必须在顶层使用

=
标记或花括号初始化列表,而不是顶层的括号。例如,即使
M(SomeClass obj(true, 3));
sizeof(SomeClass)==4
也不会编译。由于大括号初始值设定项并不完全等同于括号初始值设定项,这意味着某些声明无法与宏一起使用。


0
投票

使用 C++20,您可以在未计算的上下文中使用 lambda 来推断声明的类型,如以下

GET_TYPE
宏所示:

template <class> struct GetMethodArgument;
template <class C, class T> struct GetMethodArgument<void(C::*)(T) const> {
    using type = T;
};
template <class T> using GetLambdaArgument = typename GetMethodArgument<decltype(&T::operator())>::type;
#define GET_TYPE(decl) GetLambdaArgument<decltype([](decl){})>

其工作方式是,宏创建一个 lambda,并将声明作为参数,然后将该 lambda 的类型传递给某个提取参数类型的模板机制。我在 Carbon 代码库中发现了这个技巧。

您现在可以使用该宏来解决您的问题:

#define M(declaration) \ declaration; \ static_assert(sizeof(GET_TYPE(declaration)) == 4, "!") M(int i); M(double d = 3.14); M(std::string s = "Hello, world!");
请注意,该宏仅适用于有效函数参数的声明,因此它不适用于 

double d{3.14}

© www.soinside.com 2019 - 2024. All rights reserved.