2014-03-06 92 views
1

我有一個模板類template<typename T> Foo,它使用了某些功能T。然而,事實證明,即使沒有T具有所有必要的成員函數,代碼也可以編譯。一個例子如下。確保C++模板不會編譯時丟失的函數

template<class T> 
struct Foo { 
    T t; 
    int foo() { 
     return t.foo(); 
    } 

    int bar() { 
     return t.bar(); 
    } 
}; 

struct baz { 
    int foo() { 
     return 42; 
    } 
}; 

int main() { 
    Foo<baz> x; 
    return x.foo(); 
} 

我怎樣才能確保代碼不會編譯如果T不提供所有必要的功能?我知道如果我使用包含所有繼承的基類並從中派生,就可以做到這一點。不過,如果可以在沒有太多附加代碼的情況下使用模板,我將非常感激。

我在Linux上使用gcc 4.8.2。

+2

當代碼編譯,缺少的功能,難言*技術上*必要的。他們在什麼意義上是必要的? –

+0

如果你想玩一些即將到來的C++功能,你可以嘗試[概念](http://isocpp.org/blog/2013/02/concepts-lite-constraining-templates-with-predicates-andrew-sutton-bjarne -s)。 – Cornstalks

+0

在運行代碼的意義上,它們不是「必需的」。但它會很好,因爲有時候我忘了給'T'添加一個函數,然後直到實際使用該函數後才被捕獲。 –

回答

3

爲了要求類型是具有某些可訪問成員函數的類類型,只需引用它們即可。例如。在Foo每個構造可以說

Foo() 
{ 
    (void) sizeof(decltype(t.foo())); 
    (void) sizeof(decltype(t.bar())); 
} 

以上是比你的榜樣需要多一點,但顯示瞭如何輕鬆地確保該功能調用某些參數,還是有一定的簽名。

或者你可以在static_assert中輸入這樣的表達式。

2

到@Cheers答案相似,但有點更通用的(工程,即使Foo不包含T):

template<typename...> 
struct test {}; 

template<typename T> 
using Foo_test = test< 
    decltype(std::declval<T>().foo()), 
    decltype(std::declval<T>().bar()) 
>; 

template<class T> 
struct Foo : Foo_test<T> { 
    // ... 
}; 

這個問題涉及到概念目前正在爲C設計++ 14,所以未來這種測試可能會更方便。

+0

這種測試具有無論功能結果類型如何都能正常工作的優點,但缺點一目瞭然。我的答案中的測試對於手邊的情況具有簡單的優點,但例如,不處理void函數結果(如書面所示)。我在介紹通用與特定案例代碼之間搖擺不定,但選擇了後者,堅持KISS原則。 –

+0

@Cheers好吧,我準備編輯我的答案,使其更具通用性,所以我應該停下來:-) – iavr

0

以你的代碼,我會簡單地使用static_assertstd::is_member_function_pointer如下(文檔here

template<class T> 
struct Foo { 
    static_assert(std::is_member_function_pointer<decltype(&T::foo)>::value, ""); 
    static_assert(std::is_member_function_pointer<decltype(&T::bar)>::value, ""); 
    T t; 
    int foo() { 
     return t.foo(); 
    } 

    int bar() { 
     return t.bar(); 
    } 
}; 

struct baz { 
    int foo() { 
     return 42; 
    } 
}; 

int main() { 
    Foo<baz> x; 
    return x.foo(); 
}