2012-01-15 17 views
4

如果我有一個方法,接受,應該是轉換爲,base_of,或同一類型的返回類型的模板參數,我應該怎麼辦?如何期待static_assert失敗並使用Boost.Test框架處理它?

例如,考慮這種方法:

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

您是否試圖通過嘗試傳遞完全不相關的'Foo'參數來測試只接受'Bar'參數的函數。 static_assert是一個編譯時構造,因此您不需要測試該約束? – 2012-01-15 14:40:15

+0

@parapura rajkumar,你是對的。單元測試只證明它是類型安全的 - 我想捕獲static_assert失敗並將它們提升到更高的級別。我希望儘可能接近開發代碼的static_assert失敗,因此編譯錯誤更相關。 – 2012-01-15 14:53:41

+1

@mister爲什麼你不需要相信你的用戶知道他們在某些時候編碼了什麼? – 2012-01-15 16:14:17

回答

6

爲了您的信息,編譯時故障通常防止編譯...這就是爲什麼他們在這裏畢竟。

我能想到的兩種方式,做你所建議的:

  • 使用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條件滿足時發出錯誤。因此編譯器可能有這個鉤子。

例如,在鏘測試套件一個可以找到一個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正確滿足。

如果它們不是,那麼編譯器將返回一個錯誤代碼。當然,這很可能是編譯器特有的。