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

参考までに、コンパイル時の失敗は通常、コンパイルを妨げます...これが、結局ここにある理由です。

あなたが提案していることを行うには、次の2つの方法が考えられます。

  • 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

( ideoneoperator+(Foo, Bar)を参照)どこにも定義されていませんが。

残念ながら、これはすべてのケースで機能するとは限りません (まだ不明です) が、準拠しているすべてのコンパイラで移植できるはずです。

コンパイラ固有

もう 1 つの可能性は、コンパイラ固有の機能を使用することです。コンパイラ テスト スイートは、これらのコンパイラがエラーを正しく診断していることを確認する必要があります。この場合、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回避とは、指定された と が正しく満たされていることをコンパイラがチェックすることを意味します-verifyexpected-noteexpected-warningexpected-error

そうでない場合、コンパイラはエラー コードを返します。もちろん、これはコンパイラ固有のものである可能性があります。

于 2012-01-15T17:04:45.990 に答える