簡體   English   中英

C++ - 指定模板值類型

[英]C++ - Specify template value type

我有 function

// Helper to determine whether there's a const_iterator for T.
template <typename T>
struct hasConstIt {
private:
    template<typename C> static char test(typename C::const_iterator*);
    template<typename C> static int test(...);
public:
    enum { value = sizeof(test<T>(0)) == sizeof(char) };
};

// Check if a container contains an element.
template <typename Container, typename = std::enable_if_t<hasConstIt<Container>::value> >
bool contains(const Container & container, typename Container::value_type const & element) {
    return std::find(container.begin(), container.end(), element) != container.end();
}

如何指定容器值類型必須是特定類型? 假設我希望容器包含int ,那么有效容器可以是vector<int>deque<int>等。

您可以使用std::is_same_vstatic_assert來完成它。

template <typename Container>
bool contains(const Container& container, typename Container::value_type const& element) {
    static_assert(std::is_same_v<typename Container::value_type, int>, "The container 'value_type' must be 'int'!");

    // You don't have to explicitly check if there is a 'const_iterator' because the STL containers specify 'cbegin()' and 'cend()'
    // which returns the 'Container::const_iterator'. So checking if these functions are there will be enough (for STL containers).
    return std::find(container.cbegin(), container.cend(), element) != container.cend();
}

現在如果Container::value_type不是int ,它會拋出一個編譯器錯誤,指出The container 'value_type' must be 'int'!

獎勵:您的hasConstIt可以用更好的方式編寫(更具可讀性,IDE 不會抱怨函數未定義),

template <typename T>
struct hasConstIt {
private:
    template<typename C> static constexpr bool test(typename C::const_iterator*) { return true; }
    template<typename C> static constexpr bool test(...) { return false; }
public:
    static constexpr bool value = test<T>(nullptr);
};

現在您可以使用另一個static_assert來明確檢查Container是否有const_iterator 此步驟是可選的。

您可以使用std::is_same檢查類型是否與指定的類型完全相同。 如果您想同時檢查兩個條件,您可以簡單地在std::enable_if條件中使用邏輯運算符:

template <typename Container, typename = std::enable_if_t<
    (std::is_same<typename Container::value_type, int>::value &&
    hasConstIt<Container>::value)
    > >
bool contains(const Container & container, typename Container::value_type const & element) {
    return std::find(container.begin(), container.end(), element) != container.end();
}

與其他答案相反,這是 SINAE 友好的。 但是,如果您只想確保在用戶犯錯時它不會編譯,我會選擇 go 和其他解決方案,因為它會為您提供更好的錯誤消息。

這里的例子。

如果您可以使用 C++20,則可以使用requires來約束您的模板類型。 這既是 SFINAE 友好的,又會給你一個很好的錯誤信息。

template<typename Container>
requires (
    requires {
     typename Container::const_iterator; 
     typename Container::value_type; 
    } 
    && std::same_as<typename Container::value_type, int>
)
bool contains (const Container & container, typename Container::value_type const & element) {
    return true;
}

或者,如果您需要約束多個功能,您可以定義一個概念

template<typename Container>
concept good_container = 
  requires(Container c) {        
   typename Container::const_iterator; 
   typename Container::value_type;                 
  } 
  && std::same_as<typename Container::value_type, int>;

template<good_container Container>
bool contains (const Container & container, typename Container::value_type const & element) {
    return true;
}

這里的例子。

hasConstIt在這里看起來是多余的。 可以使用std::void_t 技巧對其進行簡化。 你可以寫:

template <typename Container, typename = std::void_t<typename Container::const_iterator>>
bool contains(/* ... */);

如果Container具有const_iterator成員類型,它將被std:void_t轉換為void ,如果沒有,SFINAE 將介入。這是一種通用技術,但在這種特殊情況下,您可以進一步 go 並省略std::void_t

template<typename Container, typename = typename Container::const_iterator>
bool contains(/* ... */);

要在元素類型上嵌入附加約束,您只需以標准方式添加另一個虛擬模板參數:

template<typename Container,
         typename = typename Container::const_iterator,
         typename = std::enable_if_t<std::is_same_v<typename Container::value_type, int>>>
bool contains(/* ... */);

暫無
暫無

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

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