如何预期static_assert失败并使用Boost.Test框架进行处理

How to expect a static_assert failure and deal with it using Boost.Test framework?

本文关键字:Test Boost 框架 处理 static 何预期 assert 失败      更新时间:2023-10-16

如果我有一个方法接受一个模板参数,该参数应该转换为、base_of或与返回的类型相同的类型,我应该怎么做?

例如,考虑这种方法:

template <class T>
class IFoo
{
public:
    template <class ServiceT>
    T* as()
    {
        static_assert(std::is_same< T, ServiceT >::value
                      || std::is_convertible< T, ServiceT >::value
                      || std::is_base_of< ServiceT, T >::value,
                      "IFoo< T >::as< ServiceT >() requires ServiceT to be a base of T");
        ...
    }
};

现在,我想BOOST_CHECK!

class A {};
class B {};
BOOST_AUTO_TEST_CASE(registering_incompatible_types_should_raise_a_static_assert_failure)
{
    BOOST_CHECK_STATIC_ASSERT_FAILURE(IFoo< A* >().as< B* >());
}

我希望这个BOOST_CHECK编译良好并通过。但是,我希望用户代码在实际执行以下操作时编译失败:

void myAwesomeMethod()
{
    auto result = IFoo< A* >().as< B* >();
    ...
}

知道吗?

仅供参考,编译时失败通常会阻止编译。。。这就是他们来这里的原因。

我可以想出两种方法来实现你的提议:

  • 使用SFINAE
  • 使用编译器特定的选项

SFINAE

从字面上看,SFINAE的意思是:替换失败不是错误。它适用于模板上下文,并允许从重载集中悄悄丢弃被证明不充分的函数。SFINAE的使用产生了概念检查的概念,并使用用于支持这些检查的特征对属性进行分类。

在您的情况下,这意味着如果您可以以某种方式将要测试的表达式放在SFINAE可能应用的上下文中,那么您可以尝试检测特定函数是否已被有效丢弃。

例如:

#include <iostream>
#include <utility>
struct Foo {};
struct Bar {};
template <typename T>
auto foo(T t) -> decltype(std::declval<Foo>() + t) { std::cout << "Tn"; }
void foo(...) { std::cout << "ellipsisn"; }
int main() { foo(Bar()); }

收益率:

ellipsis

(参见ideone),即使在任何地方都没有定义operator+(Foo, Bar)

不幸的是,这可能不适用于所有情况(还不确定),但它应该可以在所有兼容的编译器上移植。

编译器特定

另一种可能性是使用编译器特定的功能。编译器测试套件必须验证这些编译器是否正确诊断了错误,在您的情况下,当满足static_assert条件时,确实会发出错误。因此,编译器可能对此有钩子。

例如,在Clang测试套件中,可以找到一个SemaCXX/static-assert.cpp文件:

// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
int f();
static_assert(f(), "f"); // expected-error {{static_assert expression is not an integral constant expression}}
static_assert(true, "true is not false");
static_assert(false, "false is false"); // expected-error {{static_assert failed "false is false"}}
void g() {
    static_assert(false, "false is false"); // expected-error {{static_assert failed "false is false"}}
}
class C {
    static_assert(false, "false is false"); // expected-error {{static_assert failed "false is false"}}
};
template<int N> struct T {
    static_assert(N == 2, "N is not 2!"); // expected-error {{static_assert failed "N is not 2!"}}
};
T<1> t1; // expected-note {{in instantiation of template class 'T<1>' requested here}}
T<2> t2;
template<typename T> struct S {
    static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static_assert failed "Type not big enough!"}}
};
S<char> s1; // expected-note {{in instantiation of template class 'S<char>' requested here}}
S<int> s2;

-fsyntax-only避免代码生成,-verify表示编译器检查指定的expected-noteexpected-warningexpected-error是否正确满足。

如果不是,则编译器将返回错误代码。当然,这可能是编译器特有的。