Как ожидать сбоя static_assert и бороться с ним с помощью фреймворка Boost.Test? - PullRequest
4 голосов
/ 15 января 2012

Если у меня есть метод, принимающий параметр шаблона, который должен быть преобразован в, 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* >();

    ...
}

Есть идеи?

1 Ответ

6 голосов
/ 15 января 2012

К вашему сведению, сбой во время компиляции обычно мешает компиляции ... вот почему они все-таки здесь.

Я могу придумать два способа сделать то, что вы предлагаете:

  • с использованием 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 << "T\n"; }

void foo(...) { std::cout << "ellipsis\n"; }

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-note, expected-warning и expected-error правильно выполнены.

Если это не так, компилятор вернется с кодом ошибки.Конечно, это, вероятно, зависит от компилятора.

...