【问题标题】:Deduce the type of a declaration推断声明的类型
【发布时间】:2017-10-30 11:51:04
【问题描述】:

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

【问题讨论】:

  • 你打算让静态断言最后打印标识符吗?因为如果没有,还有一个解决方案也可以抛弃预处理器。
  • @StoryTeller 我不一定需要标识符。但如果你能想到多种解决方案,我会对它们都感兴趣。

标签: c++ macros type-deduction


【解决方案1】:

如果你的静态断言消息真的那么简单"!"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 - 具体来说,如果您不需要预处理器为您字符串化任何内容。

【讨论】:

  • 这解决了我的问题并让我避免使用宏,谢谢!如果我想使用static_assert 中的标识符,您是否也有解决方案?
  • @MaartenBamelis - 这需要把预处理器拖回来。它会把你带回第 1 格。
  • 那么我是否可以得出结论,在 C++ 中无法推断出声明的类型?甚至没有巧妙地结合decltype 和其他编译时技巧?
  • @MaartenBamelis - 据我所知。声明不是表达式,因此它不能出现在未计算的上下文中。也许预处理器可以将其分解。但我不熟悉这项技术。
【解决方案2】:

这个宏应该适用于你所有的例子,但它确实有一个讨厌的问题:

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

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

【讨论】:

    猜你喜欢
    • 2012-03-13
    • 1970-01-01
    • 2019-06-29
    • 2015-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多