c++ - 断言代码不能编译

标签 c++ c++11 boost compiler-errors sfinae

简而言之:

如何编写测试,以检查我的类(class)不可复制或可复制分配,但只能移动和移动分配?

一般:

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

// 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;
}

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

最佳答案

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(

把代码放在这里。请注意,它必须“提前失败”,即在函数的签名中,而不是在主体中

  )>
>:std::true_type {};

如果可以评估“将代码放在这里”,上面会生成一个测试。

要确定是否无法评估“将代码放在这里”,请否定测试结果。

template<class T>using not_t=std::integral_constant<bool, !T::value>;
not_t< my_test< int > >::value

如果“将代码放在这里”在替换阶段失败,则为真。 (或者您可以更手动地完成,通过交换上面的 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 {};

然后移动:

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 {};

并且只移动:

template<typename T>struct only_move_allowed:
  std::integral_constant<bool, move_allowed<T>::value && !copy_allowed<T>::value >
{};

上述通用技术依赖于 SFINAE。基本特征类如下所示:

template<class T, typename=void> struct whatever:std::false_type{};

这里,我们取一个类型 T ,以及第二个(匿名)参数,我们默认为 void .在工业强度库中,我们会将其隐藏为实现细节(公共(public) trait 会转发给这种私有(private) trait。

然后我们专攻。

template<typename T>struct whatever<T, /*some type expression*/>:std::true_type{};

诀窍是我们制作 /*some type expression*/计算类型为 void当且仅当我们希望我们的测试通过。如果失败,我们可以评估为非 void类型,或者只是发生替换失败。

当且仅当它的计算结果为 void我们得到 true_type .

sink_t<一些类型表达式 >技术采用 any 类型的表达式并将其转换为 void : 基本上是对替换失败的测试。 sink在图论中是指事物流入的地方,没有任何东西流出——在这种情况下,void什么都不是,类型流入其中。

对于类型表达式,我们使用 decltype(一些非类型表达式) ,这让我们可以在“假”上下文中评估它,我们只是丢弃结果。出于 SFINAE 的目的,现在评估非类型表达式。

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

非类型表达式对其类型进行评估。它实际上并没有运行,也不会导致任何 ODR 使用。所以我们可以使用std::declval<X>()生成 X 类型的“假”实例.我们使用 X&对于左值,X对于右值和 X const&对于 const左值。

关于c++ - 断言代码不能编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23547831/

相关文章:

c++ - 为什么当条件为真时 x 的值没有改变?

c++ - 我需要在此代码中调用 SafeArrayUnLock 吗?

c++ - boost::geometry 测量点到多边形环的最大/最小距离的最有效方法

c++ - 查找字母子串

c++ - 不同容器的包装器 contains() 函数

c++ - 在 boost::geometry 中初始化一个多边形

c++ - RegSetKeyValueA 函数是否有任何向后兼容的替代方法?

c++ - 在启动时运行的 Qt 程序中读取文本文件

c++ - 两个区间 [a,b] 之间的 double 随机数生成

c++ - 自定义验证器不允许 default_value