5

如果我有一个接受模板参数的方法,该参数应该可以转换为 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* >();

    ...
}

任何的想法?

4

1 回答 1

7

供您参考,编译时失败通常会阻止编译......这就是它们毕竟在这里的原因。

我可以想到两种方法来做你提议的事情:

  • 使用 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-noteexpected-warning指定expected-error是否正确满足。

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

于 2012-01-15T17:04:45.990 回答