繁体   English   中英

是否可以为不应编译的表达式表达static_assert?

[英]Is it possible to express a static_assert for an expression that should not compile?

我想用以下形式表达一个static_assert:

static_assert(expression should not compile);

让我添加一个完整的示例:

template <bool Big>
struct A{};

template <>
struct A<true>
{
    void a() {}
};

A<false> b;

static_assert(!compile(b.a()));
or
static_assert(!compile(A<false>::a()));

因此,该想法是要确保不会编译表达式(具有有效语法)。

如果可能的话,该解决方案仅使用C ++ 11会更好。

好的,鉴于您的问题的上下文含糊不清,此答案可能不适合您的情况。 但是,我发现这是一个非常有趣的挑战。

显然,如评论中所述,解决方案将必须利用某种(表达式)SFINAE。 基本上,我们需要的是检测习惯用法的更通用变体。 专家,这里主要有两个问题:

1)为了使SFINAE生效,我们需要某种模板。

2)为了提供compile(XXX)语法,我们需要在宏中“即时”创建这些模板。 否则,我们必须预先为每个测试定义一个测试函数。

第二个约束使事情变得相当困难。 我们可以在lambda内部局部定义结构和函数。 不幸的是,那里不允许使用模板。

所以这就是我能得到的距离(不是你想要的100%,而是相对接近)。

通常,表达式-SFINAE-detector利用(模板)函数重载或类模板专门化。 由于两者都不允许在lambda内,因此我们需要一个附加层:一个函子,该函子接受一堆lambda并调用最适合call参数的那个lambda。 这通常与std::variant结合使用。

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; }; 
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>; 

现在我们可以创建一个检测器,如下所示:

auto detector =    overloaded{
     [](auto, auto) -> std::false_type {return {};}
    ,
    [](auto x, int)-> decltype(decltype(x)::a(), std::true_type{}){ return {};}
    };

static_assert(!detector(A<false>{}, int{}));
static_assert(detector(A<true>{}, int{}));

现在,我们可以定义一个宏,该宏定义并调用所需表达式的dector:

#define compile(obj, xpr)                                                   \
  []() {                                                                    \
    auto check =                                                            \
        overloaded{[](auto&&, auto) -> std::false_type { return {}; },      \
                   [](auto&& x, int) -> decltype(x xpr, std::true_type{}) { \
                     return {};                                             \
                   }};                                                      \
    return decltype(check(obj, int{})){};                                   \
  }()

此宏创建一个lambda,将xpr替换为检测器,并对decltype(x)执行类型推导,以使SFINAE生效。它可以如下使用:

static_assert(!compile(b, .a()));
static_assert(compile(a, .a()));

int x = 0;
static_assert(compile(x, *= 5));
static_assert(!compile(x, *= "blah"));

不幸的是,它不能将类型名用作第一个参数。 因此,对于这些类型的AF测试,我们需要另一个宏:

#define compile_static(clazz, xpr)                                       \
  []() {                                                                 \
    auto check = overloaded{                                             \
        [](auto, auto) -> std::false_type { return {}; },                \
        [](auto x, int) -> decltype(decltype(x) xpr, std::true_type{}) { \
          return {};                                                     \
        }};                                                              \
    return decltype(check(std::declval<clazz>(), int{})){};              \
  }()

static_assert(!compile_static(A<false>, ::a()));
static_assert(compile_static(A<true>, ::a()));

如上所述,这是不是你要求什么,我们总是需要一个额外的100% ,来分隔宏参数。 另外,它需要两个单独的宏。 也许这可以通过预处理器检测xpr参数是否以::开头来解决。 而且,当然,在某些情况下,它不起作用。 但这也许是一个起点。

它需要c ++ 17,但似乎可以与gcc> = 7,clang> = 5甚至msvc 19一起使用。

这是一个完整的例子

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM