是否可以表示不应编译的表达式的静态_assert

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

本文关键字:表达式 静态 assert 编译 表示 是否      更新时间:2023-10-16

我想用以下表格表达一个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。基本上,我们需要的是检测成语的更通用变体。Hovewer,这里主要有两个问题:

1)要使Sfinae启动,我们需要某种模板。

2)要提供compile(XXX)语法,我们需要在宏中创建这些模板"即时"。否则,我们必须提前为每个测试定义一个测试功能。

第二个约束使事情变得相当困难。我们可以在Lambdas内部定义本地的结构和功能。不幸的是,模板不允许。

所以,这是我能够得到多远(不是100%您想要的,而是相对较近)。

通常,Expression-Sfinae检测器要么利用(模板)功能超载或类模板专业化。由于两者都不允许在lambda内部,因此我们需要一个额外的层:一个函子,该函子占用一堆lambdas,并将其称为最适合呼叫参数的函数。这通常与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.

这是一个完整的例子。