SFINAE断言代码不会编译 [英] SFINAE to assert() that code DOES NOT compile

查看:63
本文介绍了SFINAE断言代码不会编译的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我确信必须使用SFINAE(可能与宏一起使用)来static_assert(),这样任意代码都不会编译。

I feel certain it must be possible to use SFINAE (possibly with Macros) to static_assert() that arbitary code will not compile.

在我的代码库中有一些复杂的情况,其中我有一个我想禁止使用临时类的类(我相信这种模式是):

There are some complex cases in my code-base, where i have a class that I want to forbid taking temporaries (I believe the pattern is):

class(const class&& tmp)=delete; /* deny copying from an unnamed temporary */
class (class&& rhs){/* allow construction from non-temporary rvalue*/}

当前,我检查了不需要的构造函数,但是没有编译,但是我必须注释掉它才能使测试再次编译!

Currently, I check an undesired constructor DOES NOT compile, but then of course I have to comment it out to get the tests to compile again!

如果可以的话:

static_assert(DOES_NOT_COMPILE(myclass_t("Hello")));

const char* help = "HELP";
static_assert(!DOES_NOT_COMPILE(myclass_t(help))); 
// COMPILES() might be better here :-)

这对我有帮助很大,但是我似乎找不到通用的SFINAE解决方案。仅限于C ++ 14,因此:

That would help me a great deal, but I cannot seem to find a general SFINAE solution. C++14 only, so:

if constexpr

不可用。

推荐答案

以下宏可让您重写SFINAE -不友好的表达式,例如 [](auto&& x){return x + 1; } 以SFINAE友好的方式。

The following macro lets you rewrite a SFINAE-unfriendly expression such as [](auto&&x) { return x+1; } in a SFINAE-friendly way.

#define RETURNS(...)\
  noexcept(noexcept(__VA_ARGS__))\
  ->decltype(__VA_ARGS__)\
  { return __VA_ARGS__;}

因此,您可以这样重写上述lambda表达式:

So that lets you rewrite the above lambda expression like this:

[](auto&&x) RETURNS( x+1 )

,或者,另一个示例:

struct { template<class X> auto operator()(X&&x) RETURNS(x+1) };

,它对SFINAE友好。实际上并不需要 RETURNS ,但是它使大部分代码更加简洁。有一个c ++ 20 建议用SO自己的@barry将 RETURNS 替换为 =>

and it is SFINAE friendly. RETURNS isn't actually required, but it makes much of the code so much cleaner. There is a c++20 proposal to replace RETURNS with => by SO's own @barry.

接下来,我们需要测试是否可以调用函数对象。

Next we need to be able to test if a function object can be called.

namespace details {
  template<class, class, class...>
  struct can_invoke:std::false_type{};
  template<class F, class...Args>
  struct can_invoke<
    F,
    std::void_t<std::result_of_t<F&&(Args&&...)>>,
    Args...
  >:
    std::true_type
  {};
}
template<class F, class...Args>
using can_invoke=details::can_invoke<F,void,Args...>;

我们快到了。 (这是该技术的核心;我有时会使用 can_apply 接受 template< class ...> class Z 而不是这里的 F类。)具有相似的特征;

we are almost there. (This is the core of the technique; I sometimes use can_apply that takes template<class...>class Z instead of class F here.) c++17 has a similar trait; it can be used instead.

test_invoke 可调用并返回可调用的测试器。可调用的测试器接受参数,并根据可以使用这些参数调用原始可调用对象返回真假类型。

test_invoke takes callable and returns a callable tester. A callable tester takes arguments, and returns true or false types based on "could the original callable be called with these arguments".

template<class F>
constexpr auto test_invoke(F&&){
  return [](auto&&...args) RETURNS( can_invoke< F, decltype(args)... >{} );
}

,我们到了。如果您愿意使用纯类型,可以跳过 test_invoke ,但是使用值可以消除一些错误。

and here we are. test_invoke can be skipped if you are willing to work with pure types, but working with values can eliminate some bugs.

auto myclass_ctor=[](auto&&...args)RETURNS(myclass_t(decltype(args)(args)...));

myclass_ctor 是表示构造的可调用对象 myclass_t

myclass_ctor is a callable object that represents constructing myclass_t.

static_assert(!test_invoke(myclass_ctor)("Hello") );

template<class C>
auto ctor=[](auto&&...args)RETURNS(C(decltype(args)(args)...));
static_assert(!test_invoke(ctor<myclass_t>)("Hello") );

这需要constexpr lambda,即功能,但功能较早。没有它就可以做到,但是很难看。另外,动词ctor的要求很烦人,无法在

this requires constexpr lambda, a c++17 feature but an early one. It can be done without it but it gets ugly. Plus move ctor requirement of elision is annoying to work around in c++14.

要翻译为,将每个lambda替换为具有适当constexpr特殊成员函数的手动函数对象。如上所述,返回值同样适用于 operator()

To translate to c++14, replace every lambda with a manual function object with appropriate constexpr special member functions. RETURNS applies to operator() just as well, as demonstrated above.

要绕过elevance移动ctor要求,请 RETURNS(void(blah))

To get around elision move ctor requrement, RETURNS(void( blah )).

道歉对于任何打字;我在打电话。

Apologies for any tyops; I am on phone.

这篇关于SFINAE断言代码不会编译的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆