簡體   English   中英

C++ 檢查 class 是否源自模板基礎 class; 具有完整的模板參數

[英]C++ Check if class derived from template base class; which has integral template parameters

有沒有一種方法可以測試Derived的 class 是從BaseInterface派生的,其中BaseInterface的模板參數是無符號整數值? 我想將此檢查作為模板 std::enable_if 的一部分執行。 BaseInterface有一個方法,該方法接受對字節塊的引用,該塊的大小將取決於OutputSize模板參數。

template < size_t BlockSize, size_t OutputSize >
class BaseInterface {
public:
    const static size_t BLOCK_SIZE = BlockSize;
    const static size_t OUTPUT_SIZE = OutputSize;
    using Output = uint8_t[ OutputSize ];
    virtual ~BaseInterface() = default;
    virtual void update( uint8_t*, size_t ) = 0;
    virtual void getOutput( Output& ) = 0;
};

class Derived : public BaseInterface< 64, 16 > {
public:
    ...
};

我看到有評論提到可以這樣做,但它會比通常的 std::is_base_of 或 std::derived_from 更復雜。 當然,我還沒有找到這種“更復雜的方式”的任何實例。
因為模板參數不是類型,而是無符號整數值,所以這些都不起作用。 我想我最感興趣的是接口是否存在於通過模板傳入的 class 中。 我總是可以檢查每個方法,typedef 和常量。 這可能會很煩人......因此,如果有更好的方法可以做到這一點,請隨時說出來。

template < typename ImplementedInterface,
    typename = typename std::enable_if<
            ... other checks here ...
            is_derived< Derived, Base ??? >
        >::type >
void method( ... input here ... ) {
    ImplementedInterface ii;
    ImplementedInterface::Output out;
    ii.update( ... );
    ii.output( out );
}

同時,我將弄清楚檢查派生的 class 以獲取所需接口需要做多少工作。

檢測基本 class 模板實際上很容易,只要它明確且可訪問,例如:

template <size_t BlockSize, size_t OutputSize>
size_t get_block_size(const BaseInterface<BlockSize, OutputSize>&) {
    return BlockSize;
}

get_block_size(Derived{});  // returns 64

這是因為雖然模板參數推導通常需要“精確匹配”,但當參數類型是派生的 class 類型時,此規則有一個例外。 在這種情況下,如果派生的 class 類型無法成功推導模板參數,則編譯器會嘗試使用參數類型的基本 class (繼續向上 inheritance 層次結構),直到推導成功。 1

您可以使用此功能輕松構建所需的類型特征。

1此規則僅適用於參數類型為simple-template-id或指向simple-template-id 的指針; C++20 [temp.deduct.call]/4.3。

免責聲明:這個答案主要基於@Jarod42 對另一個問題的回答

雖然@Brian 的答案可能適用於您的特定情況,但在您需要使用派生類型做更復雜的事情的情況下(例如,將其向上轉換為 BaseType<64, 16> 不是一個選項,可能是因為您需要在某處保持類型一致性),那么這是一個更通用的解決方案:

template<typename T>
struct is_derived_from_base_interface {
private:
    template<size_t S1, size_t S2>
    static decltype(static_cast<const BaseInterface<S1, S2>&>(std::declval<T>()), std::true_type{})
        test(const BaseInterface<S1, S2>&);
    static std::false_type test(...);
public:
    static constexpr bool value =
        decltype(is_derived_from_base_interface::test(std::declval<T>()))::value;
};

int main() {
    // prints 1, for true
    std::cout << "Derived is derived from BaseInterface: " << is_derived_from_base_interface<Derived>::value << "\n";
    // prints 0, for false
    std::cout << "Derived is derived from BaseInterface: " << is_derived_from_base_interface<std::string>::value << "\n";
    return 0;
}

您可以將它與std::enable_if一起使用,如下所示:

template<typename T>
typename std::enable_if<is_derived_from_base_interface<T>::value>::type my_function(T&& arg) {
    // Do something
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM