Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
256 views
in Technique[技术] by (71.8m points)

C++ - Specify template value type

I have the 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();
}

How can I specify that the container value type must be a specific type? Say I want the container to contain int, then valid containers could be vector<int>, deque<int> etc.

question from:https://stackoverflow.com/questions/65950762/c-specify-template-value-type

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can use std::is_same to check if a type is exaclty the same as a specified one. If you want to check both of your conditions at once, you can simply use logical operators in the std::enable_if conditon:

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();
}

Contrary to the other answer, this is SINAE friendly. But if you only want to make sure it does not compile if the user makes a mistake I'd go with the other solution because it will give you way better error messages.

Example here.

If you can use C++20 you can use requires to constrain your template types. This is both SFINAE-friendly and gives you a nice error message.

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;
}

Or, if you need to constrain multiple functions you can define a concept

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;
}

Example here.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...