Multiple std::hash specialisation [duplicate] - c++

This question already has answers here:
Specializing `std::hash` for classes meeting condition
(3 answers)
Closed 1 year ago.
I have a class
class Base {
...
virtual size_t GetHash() = 0;
...
};
and a number of classes, inherited from Base, that override GetHash().
I want to use these classes as a key in unordered_map or unordered_set. Currently I achieve it by using
struct HashKey
{
template <typename T>
size_t operator()(const T & obj) const
{
return obj.GetHash();
}
};
as a Hash class in unordered_map template (like unordered_map<MyDerived, int, Hashkey>).
According to this question, I can explicitly specialize std::hash<T> for my own class and totally works fine, but I'm interested if there any way to specialize it for multiple classes?
I'm using C++17

Yes. Make it work for all T where T has a base class of Base.
Without requires, this is done using SFINAE and enable_if.

Related

C++11 template: How to ensure that the type inherits a class? [duplicate]

This question already has answers here:
How to force template <class> to be derived from BaseClassA?
(3 answers)
Closed 2 years ago.
In Java generic, when I want to ensure that the type of some generic class must inherit a class, I can code as below:
public class MyHandler<T extends Serializable> {}
This means that T must extend/implement the class/interface Serializable, otherwise, the compiler will generate an error.
How to get the same thing in C++11? I mean, if I code C++11 as below:
template<typename T>
class MyHandler {}
In this piece of code, T can be any class. But, if I want to tell the class users that T must inherit the class boost::archive::text_oarchive (just like <T extends Serializable> in Java), what can I do?
You can use std::is_base_of for checking.
template<typename T>
class MyHandler {
static_assert(std::is_base_of<boost::archive::text_oarchive, T>::value, "T must inherit boost::archive::text_oarchive");
};
Since C++20 we can use constraint, e.g.
template<typename T> requires std::is_base_of_v<boost::archive::text_oarchive, T>
class MyHandler {};

Template member switch using enable_if and is_default_constructible [duplicate]

This question already has answers here:
Member function template selection and SFINAE
(1 answer)
SFINAE not working to conditionally compile member function template
(1 answer)
Approaches to function SFINAE in C++
(2 answers)
Closed 2 years ago.
I want to switch between to members of a templatized class based on the fact the type of the template is default constructible or not.
I think I'm not far from the solution after a lot of reading and tries around std::enable_if and std::is_default_constructible, but I'm still stuck at compile-time, here's a minimized exemple :
template<typename DataType>
class MyClass{
public:
template < typename = typename std::enable_if_t<std::is_default_constructible_v<DataType>>>
inline void createNew(unsigned int index) {
new (&this->buffer[index]) DataType(); // "placement new"
}
template < typename = typename std::enable_if_t<!std::is_default_constructible_v<DataType>>>
inline void createNew(unsigned int index) {
throw BaseException("No default constructor");
}
};
This last try results on "member function already defined or declared". I think I miss something, but I don't understand why both functions are selected for compilation even if they have the exact opposite template condition.

Force the user to pass a template parameter of a known type which is itself templated [duplicate]

This question already has answers here:
How to know if a type is a specialization of std::vector?
(5 answers)
Closed 3 years ago.
Suppose I have a class
template <typename T>
struct Foo {
T data;
};
where I want to enforce the fact that T is a known templated type. For instance, suppose that I want T to be a std::vector of something. Now one way to handle this problem would be to redefine the class so that the template parameter is also the template parameter of the data function:
template <typename S>
struct Foo {
std::vector<S> data;
};
I do not want to do that. In this specific case, it feels more natural to require the user to construct a foo object like this:
Foo<T<S>> f;
which, in the case where we want T to be a vector, looks like
Foo<std::vector<S>> f;
Is there anyway to keep the first form of the class, which requiring that T be of a specific class? Perhaps a static_assert?
Got it
template <typename T>
struct Foo {
static_assert( std::is_same<T,std::vector<T::value_type>>::value, "T is not a vector you idiot" );
};

Use cases of keyword using in C++11 [duplicate]

This question already has answers here:
What is the logic behind the "using" keyword in C++?
(2 answers)
Closed 2 years ago.
I know using in C++11 behaves same as typedef. I have this code and found different use cases:
template<typename T, int a>
class Base
{
public:
std::vector<T> noise_(a);
using VectorType = std::vector<T>;
virtual VectorType getVector() const
{
return noise_;
}
protected:
VectorType noise_;
};
template<typename T, int a>
class Derived : public Base<T,a>
{
public:
using Base<T,a>::noise_;
using VectorType = typename Base<T,a>::VectorType;
using Base<T,a>::getVector;
};
Here, using is used in 3 different way. What is the purpose of the following line (noise_ is a protected member of the base class):
using Base<T,a>::noise_;
Same for:
using Base<T,a>::getVector;
Simply put, when the base class depends on a template parameter, its scope is not inspected to resolve names. Hence, you cannot refer to noise_ in Derived using just noise_. You should either write this->noise_, or introduce the name with using.

Template class and forcing certain methods to be implemented by User [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is it possible to write a C++ template to check for a function's existence?
I am trying to write a C++ class template. What I want is when this class template is used with user defined classes, I want to force those user defined classes to implemented certain methods say e.g., to_data and from_data. I do not want those for basic C++ primitive datatypes. How do I do this? For example, std::vector give compilation error if the copy constructor of the class is not available.
You can make the methods that must be implemented by user pure virtual functions. If you don't want those for basic C++ primitive datatypes, you can specialize your template for these situations and provide default implementations for these cases.
Simply use the methods in your class template:
template <typename T>
struct Serializer
{
void serialize(T const & t) const { write(t.to_data()); }
void deserialize(T & t) const { t.from_data(read()); }
};
If the types you instantiate the template with have the appropriate member functions, everything will be fine. If they don't, the compiler will trigger an error:
struct Foo
{
int val;
int to_data() const { return val; }
void from_data(int i) { val = i; }
};
struct Bar {};
Serializer<Foo> sf;
sf.serialize(); // OK
Serializer<Bar> sb;
sb.serialize(); // compiler error: Bar has no member function named "to_data"
Note that the compiler error is only triggered when we try to use some functions of the class template. This is because member functions of class templates are only instantiated (compiled, if you will) when you use them. So it is perfectly fine to instantiate Serializer with Bar as long as you don't use the serialize and deserialize member function.
Regarding the second issue, namely how to provide a different behavior for primitive types, you have several solutions. The first one is to specialize your class template for the types you want to handle differently. For instance, the following code specializes Serializer so that it handles int differently:
template <>
struct Serializer<int>
{
void serialize(int i) const { write(i); }
void deserialize(int & i) const { i = read();
};
However, this implies writing a specialization for each particular type, even if some of them are in fact handled in the same way.
A less cumbersome solution would be to use type traits and std::enable_if to select the correct implementation depending on some characteristics of the arguments types (in this case, whether they are primitive or not):
#include <type_traits>
template <typename T, typename Enable = void>
struct Serializer
{
// same as before
};
// Partial specialization for fundamental types
template <typename T>
struct Serializer<T, typename
std::enable_if<std::is_fundamental<T>::value>::type>
{
void serialize(T t) const { write(t); }
void deserialize(T & t) const { t = read(); }
};
Serializer<Foo> sf; // first implementation
Serializer<int> si; // second (specialized) implementation