SFINAE断言()代码不编译

时间:2018-03-03 00:01:02

标签: c++ c++14 sfinae

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

在我的代码库中有一些复杂的情况,我有一个我想禁止接受临时工作的课程(我相信模式是这样的):

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

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

如果我能做到:

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,所以:

if constexpr

不可用。

1 个答案:

答案 0 :(得分:12)

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

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

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

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

这是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...>;
我们快到了。 (这是该技术的核心;我有时会使用can_apply来取代template<class...>class Z而不是class F。)具有相似的特征;它可以用来代替。

test_invoke需要可调用并返回一个可调用的测试器。一个可调用的测试器接受参数,并根据&#34返回true或false类型;可以使用这些参数调用原始的callable&#34;。

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

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

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

myclass_ctor是一个可调用对象,表示构造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对elision的要求很烦人,可以在中解决。

要翻译为,请使用具有相应constexpr特殊成员函数的手动函数对象替换每个lambda。 RETURNS也适用于operator(),如上所示。

为了解决问题,需要RETURNS(void( blah ))

道歉;我正在打电话。