SFINAE断言()代码不编译

r w*_*bby 7 c++ sfinae c++14

我确信必须能够将SFINAE(可能带有宏)用于static_assert(),而仲裁代码将无法编译.

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

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

目前,我检查一个不需要的构造函数不能编译,但当然我必须将它注释掉以便再次编译测试!

如果我能做到:

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 :-)
Run Code Online (Sandbox Code Playgroud)

这对我有很大的帮助,但我似乎无法找到一般的SFINAE解决方案.仅限C++ 14,所以:

if constexpr
Run Code Online (Sandbox Code Playgroud)

不可用.

Yak*_*ont 14

#define RETURNS(...)\
  noexcept(noexcept(__VA_ARGS__))\
  ->decltype(__VA_ARGS__)\
  { return __VA_ARGS__;}
Run Code Online (Sandbox Code Playgroud)

这让你可以像这样写一个lambda表达式:

[](auto&&x) RETURNS( x+1 )
Run Code Online (Sandbox Code Playgroud)

要么

struct { template<class X> auto operator()(X&&x) RETURNS(x+1) };
Run Code Online (Sandbox Code Playgroud)

这是SFINAE友好的. RETURNS实际上并不是必需的,但它使得大部分代码更加清晰.有一个的建议,以取代RETURNS=>被SO自己@barry.

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

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...>;
Run Code Online (Sandbox Code Playgroud)

我们就快到了.(这是该技术的核心;我有时使用can_apply的是需要template<class...>class Z的,而不是class F在这里.) 也有类似的性状; 它可以用来代替.

test_invoke需要可调用并返回一个可调用的测试器.可调用测试器接受参数,并根据"可以使用这些参数调用原始可调用对象"返回true或false类型.

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

我们在这里. test_invoke如果你愿意使用纯类型,可以跳过,但使用值可以消除一些错误.

auto myclass_ctor=[](auto&&...args)RETURNS(myclass_t(decltype(args)(args)...));
Run Code Online (Sandbox Code Playgroud)

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

static_assert(!test_invoke(myclass_ctor)("Hello") );
Run Code Online (Sandbox Code Playgroud)

要么

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

这需要constexpr lambda,一个功能,但是早期功能.它可以在没有它的情况下完成,但它变得丑陋.另外,移动ctor对elision的要求很烦人,可以在.

要转换为,请使用具有相应constexpr特殊成员函数的手动函数对象替换每个lambda. 如上所述,同样RETURNS适用operator()于此.

为了避开elision移动ctor requrement , RETURNS(void( blah )).

为任何打扰道歉; 我在打电话.

  • 该死的,耐心。 (2认同)