这种立即使用和未定义的宏有什么缺点?

时间:2015-07-29 18:29:37

标签: c++ c-preprocessor

我仍然不确定问这个问题是否是一个好主意,因为它以某种方式编码风格"问题(那些本质上是主观的),但我希望它能够客观地转向那种方式 如果事实证明它不是,我很抱歉在这里问。

我想问两个问题:

  • 与复制粘贴我可以忽略的实际代码相比,使用该宏有什么重要的缺点吗? (或者你能想到的任何更好的解决方案)
  • 有没有更好的解决方案来实现同样的目标? (避免重复"样板元编程代码")

然而,我不知道你是否喜欢这个代码。如果你愿意,我无法阻止你这么说,如果你这么做我就不会介意,但是我想知道它为什么好或坏了可能有助于将这个问题引向潜在的基于意见的问题的黑暗面(假设它已经,我再次道歉,如果是的话)。

最近,我想写一些特征,其中很多都非常简单。但是,每个都需要某种重复的元编程代码。我最终使用宏来使代码更紧凑,重复性更低,使用如下代码:

#include <type_traits>
//...
template<class...>
struct void_type {
  typedef void type;
};

template<class... T>
using void_t = void_type<T...>::type;

#define UNARY_EXPRESSION_TYPE_TRAIT(trait_name, expression, expression_type,  \
                                    type_name)                                \
namespace detail_generated  {                                                 \
  template<class type_name, class = void>                                     \
  struct trait_name : std::false_type {};                                     \
                                                                              \
  template<class type_name>                                                   \
  struct trait_name<type_name, void_t<decltype(expression)>> :                \
  std::integral_constant<                                                     \
    bool, std::is_same<decltype(expression), expression_type>::value          \
  > {};                                                                       \
}                                                                             \
template<class type_name>                                                     \
struct trait_name<type_name> : detail_generated::trait_name<type_name> {};

UNARY_EXPRESSION_TYPE_TRAIT(is_preincrementable, 
                            ++std::declval<Incrementable&>(), 
                            Incrementable&, Incrementable) 
UNARY_EXPRESSION_TYPE_TRAIT(is_predecrementable, 
                             --std::declval<Decrementable&>(), 
                             Decrementable&, Decrementable) 
UNARY_EXPRESSION_TYPE_TRAIT(is_contextually_convertible_to_bool, 
                            !std::declval<T>(), bool, T) 

#undef UNARY_EXPRESSION_TYPE_TRAIT 
// ...

在这种特殊情况下,它避免重复&#34;样板元编程结构&#34;而且我没有看到很多缺点(大多数缺点都是通过立即使用宏来解决的,而且它的直接定义不明确。) 但是,我通常不会对宏感到满意(我发现它们是混淆的,通常是可替换的),我知道它们通常被认为是坏的或者是邪恶的&#34;。遗憾的是,即使在阅读了以下问题之后,我也无法找到替换它的方法,保留它的理由或避免它的理由:

(那个因为虽然不是很有用但很有趣:)

我对他们的答案不满意,因为他们要么:

  • 仅在包含警卫的情况下推荐使用宏而不解释为什么在所有其他情况下宏总是一个坏主意(我认为它们不鼓励使用宏,因为它很容易误用它们)
  • 也推荐它们用于调试功能(这里不是这种情况)
  • 说宏在某些情况下很棒然后发布一个例子我实际上发现很有劝阻
  • 声称宏是设计糟糕的标志(可能是真的,但我想知道问题出在哪里,以便我可以选择更好的解决方案)

我无法客观地判断我的代码,而且我无法找到该宏的任何良好替代品(除了实际执行预处理器的工作以及将宏复制粘贴到我需要的任何地方,不管是哪种罢工我至少同样糟糕)。也许我只是没有看到该宏的明显和致命的缺点,或者我甚至没有完全理解为什么不鼓励使用宏。

编辑:删除了注释中建议的某些名称中的前导下划线(保留此类名称)

1 个答案:

答案 0 :(得分:1)

宏的问题在于它们忽略了我们在C ++中使用的漂亮的结构化构造。 OTOH,这让我很好地利用了宏:

  • 您已将复杂的模板元编程的三个副本减少为一个
  • 您使用了一个很好的长名称,因此不太可能与头文件中定义的名称冲突。
  • 宏仅在一小段代码中定义,因此不会与该区域之外的任何内容发生冲突。

我会说“去吧”。