2017-04-19 61 views
15

當編寫自定義類型的特質,我經常得到他們的標準庫類型特點如下:從標準庫類型繼承性狀

template<typename T> 
struct some_type_trait: 
    std::is_arithmetic<T> 
{}; 

不過,我有時想,無論是從type成員類型標準的繼承庫類型特點是清潔:

template<typename T> 
struct some_type_trait: 
    std::is_arithmetic<T>::type 
{}; 

的總體思路是,只有在年底std::bool_constant事項的繼承,但其實我們從std::is_arithmetic在第一個例子繼承而不是直接從std::bool_constant(如第二種情況)可以通過多態性或實用性如std::is_base_of觀察到。

要點是,通過type成員類型直接從bool_constant繼承感覺更清潔,因爲它是正是我們想要。然而,從std::is_arithmetic繼承略短,並提供基本相同的行爲。那麼......在選擇其中一個或另一個時,我可能會錯過任何微妙的優點(正確性,編譯時間......)?與直接從底層bool_constant繼承相比,從std::is_arithmetic繼承的微妙場景可能會改變應用程序的行爲嗎?

+6

這就是一些高質量的自旋:D – Rerito

+0

FWIW,en.cppreference.com上的「可能的實現」直接繼承了'std :: integral_constant '。遵循這個「風格」,你的例子將繼承自'std :: integral_constant :: value>'。 –

+0

@DanielJour如果我沒有弄錯,從'std :: integral_constant'繼承對類型特徵是強制性的。問題是直接從'std :: integral_constant'直接通過':: type'派生,還是通過類型特徵本身間接派生是更好。也許我不明白你的意見:/ – Morwenn

回答

1

第二個漏洞實施細節漏洞小;如果你從is_arithmetic<int>或其他任何東西繼承,有人可以通過函數重載進行測試。這可能「起作用」並導致誤報。

這是一個非常小的問題。

如果您的編譯器轉儲基類名稱,您可能會從is_arithmetic繼承稍微更好的診斷。

您的設計都不合適。相反:

template<class T> 
struct some_type_trait: 
    std::integral_constant<bool, 
    std::is_arithmetic<T>{} 
    > 
{}; 

可以擴展,因爲我們可以把任何表達式放在那裏。

正如我前面提到的,錯誤消息具有類型可以是有幫助的,所以我們可以這樣做:

constexpr bool all_of() { return true; } 
template<class...Bools> 
constexpr bool all_of(bool b0, Bools...bs) { 
    return b0 && all_of(bs...); 
} 
template<class T, template<class...>class...Requirements> 
struct Requires : std::integral_constant<bool, 
    Requirements<T>{} &&... 
    // in C++11/14, something like: all_of(Requirements<T>::value...) 
> {}; 

然後我們得到:

template<class T> 
using some_type_trait = Requires<T, std::is_arithmetic>; 

如果它未能找到該過載標籤分派,會產生一個錯誤,可能會給你一個線索。

template<class T> 
void test(std::true_type passes_test, T t) { 
    std::cout << t+0 << "\n"; 
} 
template<class T> 
void test(T t) { 
    return test(some_type_trait<T>{}, t); 
} 
int main() { 
    test(3); 
    test("hello"); 
} 

可悲的是,我們沒有簡單的綁定/部分應用程序的當量/在模板元編程鑽營。所以f<.> = is_base_of<X, .>很難表達清楚。

Live example,我們得到的錯誤信息是: 鏗鏘:

main.cpp:23:10: note: candidate function [with T = const char *] not viable: no known conversion from 'some_type_trait<const char *>' (aka 'Requires<const char *, std::is_arithmetic>') to 'std::true_type' (aka 'integral_constant<bool, true>') for 1st argument 

GCC:

main.cpp:28:18: note: cannot convert 'Requires<const char*, std::is_arithmetic>()' (type 'Requires<const char*, std::is_arithmetic>') to type 'std::true_type {aka std::integral_constant<bool, true>}' 

至少導致你錯誤(即const char*不是is_arithmetic)。

+3

編譯器不會認爲它是該上下文中的值,因爲它不能是一個值。所以從'is_arithmetic :: type'繼承是好的。不必要的,但很好。 – Barry

+0

@Barry讓我無法編譯。刪除了幽默的前綴。 – Yakk