我想用以下形式表示一个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,那就更好了。
答案 0 :(得分:1)
好,鉴于您所提问题的内容含糊不清,此答案可能不适用于您的情况。但是,我发现这是一个非常有趣的挑战。
很显然,如评论中所述,该解决方案将必须利用某种类型(表达)的SFINAE。基本上,我们需要的是检测习惯用法的更通用变体。专家,这里主要有两个问题:
1)为了使SFINAE发挥作用,我们需要某种模板。
2)为了提供compile(XXX)
语法,我们需要在宏中“即时”创建这些模板。否则,我们必须提前为每个测试定义一个测试函数。
第二个约束使事情变得相当困难。我们可以在lambda内部局部定义结构和函数。不幸的是,那里不允许使用模板。
这就是我能得到的距离(不是你想要的100%,而是相对接近)。
通常,表达式-SFINAE-detectors利用(模板)函数重载或类模板专门化。由于两者都不允许在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一起使用。
这里是full example。