我确信必须能够将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
不可用。
答案 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
实际上并不是必需的,但它使得大部分代码变得更加清晰。有一个c++20提案可以将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
。)c++17具有相似的特征;它可以用来代替。
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,c++17功能但是早期功能。它可以在没有它的情况下完成,但它变得丑陋。另外,移动ctor对elision的要求很烦人,可以在c++14中解决。
要翻译为c++14,请使用具有相应constexpr特殊成员函数的手动函数对象替换每个lambda。 RETURNS
也适用于operator()
,如上所示。
为了解决问题,需要RETURNS(void( blah ))
。
道歉;我正在打电话。