断言代码不编译

Mik*_*ail 16 c++ boost compiler-errors sfinae c++11

简而言之:

如何编写测试,检查我的类是不可复制的还是可复制的,但只能移动并可移动分配?

一般来说:

如何编写测试,确保特定代码编译?像这样:

// Movable, but non-copyable class
struct A
{
  A(const A&) = delete;
  A(A&&) {}
};

void DoCopy()
{
  A a1;
  A a2 = a1;
}

void DoMove()
{
  A a1;
  A a2 = std::move(a1);
}

void main()
{
  // How to define these checks?
  if (COMPILES(DoMove)) std::cout << "Passed" << std::endl;
  if (DOES_NOT_COMPILE(DoCopy)) std::cout << "Passed" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

我想与SFINAE有关,但有一些现成的解决方案,也许是在提升?

Yak*_*ont 18

template<class T>struct sink{typedef void type;};
template<class T>using sink_t=typename sink<T>::type;

template<typename T, typename=void>struct my_test:std::false_type{};
template<typename T>struct my_test<T,
  sink_t<decltype(
Run Code Online (Sandbox Code Playgroud)

把代码放在这里.请注意,它必须"早期失败",即在函数的签名中,而不是在正文中

  )>
>:std::true_type {};
Run Code Online (Sandbox Code Playgroud)

如果可以评估"在这里放置代码",则上面生成测试.

要确定是否无法评估"此处放置代码",请取消测试结果.

template<class T>using not_t=std::integral_constant<bool, !T::value>;
not_t< my_test< int > >::value
Run Code Online (Sandbox Code Playgroud)

如果"在这里放置代码"在替换阶段失败,那将是真的.(或者你可以通过交换std::true_typestd::false_type上面的方式更多地手动完成).

在替换阶段失败不同于一般失败,因为它必须是一个表达,你在某些方面受限制.但是,要测试是否可以复制,您可以执行以下操作:

template<typename T, typename=void>struct copy_allowed:std::false_type{};
template<typename T>struct copy_allowed<T,
  sink_t<decltype(
    T( std::declval<T const&>() )
  )>
>:std::false_type {};
Run Code Online (Sandbox Code Playgroud)

并移动:

template<typename T, typename=void>struct move_allowed:std::false_type{};
template<typename T>struct move_allowed<T,
  sink_t<decltype(
    T( std::declval<T>() )
  )>
>:std::false_type {};
Run Code Online (Sandbox Code Playgroud)

并且只移动:

template<typename T>struct only_move_allowed:
  std::integral_constant<bool, move_allowed<T>::value && !copy_allowed<T>::value >
{};
Run Code Online (Sandbox Code Playgroud)

上面的一般技术依赖于SFINAE.基本特征类看起来像:

template<class T, typename=void> struct whatever:std::false_type{};
Run Code Online (Sandbox Code Playgroud)

在这里,我们采用一种类型T,以及我们默认的第二个(匿名)参数void.在一个工业强度库中,我们将其隐藏为实施细节(公共特征将转向这种私人特征.

然后我们专注.

template<typename T>struct whatever<T, /*some type expression*/>:std::true_type{};
Run Code Online (Sandbox Code Playgroud)

诀窍在于,当且仅当我们希望我们的测试通过时,我们/*some type expression*/才对类型进行评估void.如果失败,我们可以评估为非void类型,或者只是发生替换失败.

当且仅当它评估void我们得到true_type.

sink_t<某些类型的表达>技术利用任何类型的表达,并将其转化void:基本上它是用于取代发生故障的测试. sink在图论中,指的是一个物质流入的地方,没有任何东西出现 - 在这种情况下,void什么都没有,并且类型流入它.

对于类型表达式,我们使用decltype(一些非类型表达式),它允许我们在"假"上下文中对它进行评估,我们只是抛弃结果.现在针对SFINAE目的评估非类型表达式.

请注意,MSVC 2013对此特定步骤的支持有限或不支持.他们称之为"表达SFINAE".必须使用替代技术.

非类型表达式的类型得到评估.它实际上并没有运行,并且它不会导致ODR使用任何东西.所以我们可以std::declval<X>()用来生成一个类型的"假"实例X.我们使用X&了左值,X为右值,并X const&const左值.

  • 我喜欢 C++ 的表现力。 (2认同)
  • @LightnessRacesinOrbit是的 - 决定"不再为语言添加魔法,添加支持以便你可以用语言写魔术"继续支付红利. (2认同)

ten*_*our 10

您正在寻找定义的类型特征,<type_traits>以测试类型是否具有某些属性.

  • 大!一般的问题呢?即如何检查任意代码? (2认同)

Mik*_*ail 3

Andrzej Krzemie\xc5\x84ski 的一篇精彩文章“可诊断的有效性”的末尾给出了一个很好的答案:

\n\n
\n

检查给定构造是否无法编译的一种实用方法是从 C++ 外部执行此操作:准备一个带有错误构造的小型测试程序,对其进行编译,然后测试编译器是否报告编译失败。这就是 \xe2\x80\x9cnegative\xe2\x80\x9d 单元测试与 Boost.Build 一起工作的方式。有关示例,请参阅此否定测试表单 Boost.Optional 库:Optional_test_fail_convert_from_null.cpp。在配置文件中它被注释为compile-fail,意味着只有编译失败时测试才通过。

\n
\n