Implementation of abstract class without template argument - c++

I want to implement two simple abstract classes like so:
class Hashable {
public:
virtual Int hashValue() = 0;
};
template <typename T>
class Equatable {
virtual Bool operator == (const T& other) = 0;
}
These classes will give me the opportunity of partial template specialization in my new dictionary class.
However, I could not make them to work. Here is the declaration of my dictionary class:
template <Hashable Key, typename Value>
class Dictionary {
.
.
.
};
The problem is, key should also be Equatable because hashability should require it.
So, I have two questions:
Can we rewrite Equatable<T> class to have no template arguments? Does C++ have any keyword referring to current type of the class?
In my opinion, Hashable had better inherit from Equatable class. How to achieve this without new template definition on Hashable (if my first question is answered yes, this is already solved then)?
What would be the best object-oriented approach here? To have an interface class with template arguments seems tacky.
Thank you.

What you're basically looking for is Concepts, with which you'd write something like:
template <class T>
concept bool Hashable()
{
return requires(T t, T u) {
{t.hashValue()} -> size_t;
{t == u} -> bool;
};
}
template <Hashable Key, class Value>
class Dictionary {
...
};
But that won't even be in C++17.
Until then, we can write this sort of thing in C++14 using void_t:
template <class...> using void_t = void;
template <class T, class = void>
struct Hashable : std::false_type { };
template <class T>
struct Hashable<T, void_t<
std::enable_if_t<std::is_same<std::declval<T&>().hashValue(), std::size_t>::value>,
decltype(std::declval<T&>() == std::declval<T&>())
>>
: std::true_type { };
template <class Key, class Value>
class Dictionary {
static_assert(Hashable<Key>::value, "Key must be Hashable<>");
...
};
Note that in both cases, we're requiring the Key type to have this functionality - we're not requiring the Key to inherit it virtually. This is far more efficient. No virtual dispatch necessary.
What would be the best object-oriented approach here?
To not use an object-oriented approach.

I believe that
template <Hashable Key, typename Value>
does not actually do what you expect it to do. Consider:
template <int Key, typename Value> class x{};
now, you can instantiate x<1, int> and x<2, int>, but these are not merely different objects, but different types. So, in your case, your Hashable object would become part of the type (so it would have to be generated during compilation, not at runtime).
What you most probably want instead is - like Wojciech Frohmberg mentioned in the other answer:
template <typename K, typename V>
class Dict {
...
static_assert(std::is_base_of<K, Hashable>::value, "Only Hashable can be the key);
}
or enable_if or some other template magic included from type_traits.
What you're looking for are concepts, that didn't even make C++17, or typeclasses (available in other languages, like Haskell or Scala)
If you really want to use object-oriented approach here, go for something like:
template <typename Value>
class Dict {
Dict(std::shared_ptr<Hashable>, Value)
{}
}
However, it's not a typical implementation, so I wouldn't recommend it

Related

Concept of template class in C++20

I'm new in advanced usage of templates and concepts, so here is a liitle bit complex problem:
I have some Traits concept of many traits for each of Source classes:
template<typename _Traits>
concept Traits = requires
{
std::same_as<std::decay_t<decltype(_Traits::token)>, std::string_view>;
};
I have some template class that uses this concept to handle object_one with various traits (for example, half of Source classes returns object_one):
template <concepts::Traits _Traits>
class Object_one_handler final
{
static std::string handle_object(const object_one& obj) {/*...*/}
};
Then I have Objects_handlers concept of handlers for various objects from set {object_one, object_two, object_three} from various Sources with their Traits:
template<template <concepts::Traits _Traits> class _Objects_handlers, typename _Object>
concept Objects_handlers = requires(const _Object& obj)
{
// has handle_object method
{ _Objects_handlers<???????>::handle_object(obj) } -> std::same_as<std::string>;
};
Finally, I creating some database with specified as template parameter Object_handler:
template<concepts::Objects_handlers _handler>
class database
{...};
(Actually all of concepts have additional requirements, but it doesn't matter here)
So problem is in last Objects_handlers concept:
template<template <concepts::Traits _Traits> class _Objects_handlers, typename _Object>
concept Objects_handlers = requires(const _Object& obj)
{
// has handle_object method
{ _Objects_handlers<???????>::handle_object(obj) } -> std::same_as<std::string>;
^^^^^^^
};
I can't check _Objects_handlers method without template parameter (obviously) and I can't properly set the template parameter which must be one of Traits.
How can I do that?
And actually it may be problem in usage of Objects_handlers in template of database class, so one more question: how to use it?
P.S. It can be XY problem or not about concepts at all... Maybe composition with strategy pattern will be more usefull, but still want try to create this maybe useless, but workable concept.
Let's reduce this problem a lot.
template <typename T>
struct C {
void f();
};
Now, your goal is to write a concept that takes any class template (e.g. C) and checks that every specialization of it has a nullary member function named f.
template <template <typename> class Z>
concept HasF = requires (Z<???> z) {
z.f();
};
The problem is - class templates in C++ just don't work like this. Even for a particular class template, like C, you can't require that every specialization has f. There's no way to ensure that like somebody, somewhere, didn't add:
template <> struct C<std::vector<std::list<std::deque<int>>>> { };
All you can do is check that a specific type has a nullary member function named f. And that's:
template <typename T>
concept HasF = requires (T t) { t.f(); };
The type-constraint syntax, template <Concept T>, is only available for concepts that constrain types, not concepts that constrain templates or values.

Checking for template parent class in C++ using SFINAE

I've been learning the concept of SFINAE in C++ recentlly and I am currentlly trying to use it in a project.
The thing is, what I'm trying to do is different than anything I could find, and I can't figure out how to do it.
Let's say I have a template class called MyParent:
template <typename Elem>
class MyParent;
And a non-template class called MyClass, that inherites it, using char as Elem:
class MyClass : public MyParent<char>;
Now, I want to use SFINAE in order to check if a typename inherites MyParent, regardless of what Elem type is used.
I can't use std::is_base_of, because of the parent's template.
I've tried to do the following:
template <typename T>
struct is_my_parent : std::false_type {};
template <typename Elem>
struct is_my_parent<MyParent<Elem>> : std::true_type {};
Now, if I check for is_my_parent<MyParent<Elem>>::value, it gives me true. Which is good.
However, when I check for is_my_parent<MyClass>::value, I recive false. Which kind of makes sence because MyClass isn't actually MyParent<Elem>, but I didn't manage to get what I wanted.
Is there any convenient way to achive such a thing in C++, other than defining is_my_parent for each and every class that inherites from MyParent?
You might do
template <typename T>
std::true_type is_my_parent_impl(const MyParent<T>*);
std::false_type is_my_parent_impl(const void*);
template <typename T>
using is_my_parent = decltype(is_my_parent_impl(std::declval<T*>()));
Demo
Is there any convenient way to achive such a thing in C++, other than defining is_my_parent for each and every class that inherites from MyParent?
There is, but you'll need to use more elaborate meta-programming techniques. Go entirely back to basics, as it were.
template <class C>
class is_my_parent {
using yes = char;
using no = char[2];
template<typename t>
static yes& check(MyParent<t> const*);
static no& check(...);
public:
enum { value = (1 == sizeof check(static_cast<C*>(0))) };
};
It relies on two basic properties of function overloading and templates:
A derived class can be used to match a function template that takes a base class template as an argument.
Ellipsis offer a conversion sequence that is always considered worse than any other.
Then it's just a matter of inspecting the return type of the chosen overload to determine what we got. Other than the type alias, you can even use this in C++03. Or you can modernize it, so long as overload resolution does the work for you, the check will be performed just the same.
I like Jarod42's answer much better, but an actual SNINAE approach somewhat close to your attempt can work. Here's what I came up with.
To use the type_traits to answer this, we need to know the type of the element. We can make MyParent expose it:
template <typename Elem>
class MyParent {
public:
using ElemType = Elem;
};
Then the default (false) is_my_parent takes an extra arg and the void_t technique* can be used:
template <typename T, typename = void>
struct is_my_parent : std::false_type {};
template <typename T>
struct is_my_parent<T, std::void_t<typename T::ElemType>> :
std::is_base_of<MyParent<typename T::ElemType>, T>::type {};
The specialization is only valid if ElemType is an accessible type in T, and then it results in std::true|false type if the inheritance relationship holds.
live example: https://godbolt.org/z/na5637Knd
But not only is the function overload resolution a better approach for simplicity and size, it will also compile much faster.
(*) void_t was exposed to the world in this fantastic 2-part 2014 talk by Walter Brown. Recommended even if only for review.
https://www.youtube.com/watch?v=Am2is2QCvxY

Is it possible to use parameter pack instead of sequence of nested templates?

Hy, I am crafting some meta-programming library that could help to construct complex objects from simple ad-mixture classes through the inheritance.
For instance I got some mechanisms those produce a set of template classes, each representing a single property.
I`ve came to a final construction procedure that looks like this:
class Car : public Position< Size< Color< BaseObj<Car> > > > {/*...*/};
and i quite don't like it.
(BaseObj is always the most inner template in a sequence)
I tried to make some processing template to be able to write it like this:
class Car : public Proc< Position, Size, Color, Car > {/*...*/};
but got no success.
Is it possible to make such a template?
Are there any other more readable semantics those could have the same effect as a sequence of such nested templates?
So, you want...
nest<A, B, C, D>::type<E>
...to become...
A<B<C<D<E>>>>
This is a job for recursion.
template <template <typename> typename...>
struct nest;
template <template <typename> typename First,
template <typename> typename... Rest>
struct nest<First, Rest...>
{
template <typename Leaf>
using type = First<typename nest<Rest...>::template type<Leaf>>;
};
template <template <typename> typename Last>
struct nest<Last>
{
template <typename Leaf>
using type = Last<Leaf>;
};
Usage example:
template <typename> struct A { };
template <typename> struct B { };
template <typename> struct C { };
template <typename> struct D { };
struct E { };
int main()
{
static_assert(std::is_same_v<
typename nest<A, B, C, D>::template type<E>,
A<B<C<D<E>>>>
>);
}
live example on wandbox.org
Edit It appears that I misunderstood the question. I thought you wanted to change your design to simply use a list of traits, rather than having traits nested recursively. I now understand you're simply looking for a drop-in replacement that allows you to write a list, that boils down to your old design. But that leaves the question: why do you really want to stick with that design? What purpose does it serve? I'm assuming the only reason it was like that, was that you weren't able to use variadic templates before.
I think my answer is still viable, but it requires changing your current implementation of Position, Size, Color, etc. I can't really suggest how until you provide a more clear description of what those things do.
Old answer:
Well, it would be a bit easier if you put the CRTP-argument in front.
template<class S, class... P>
class Proc : public P...
{
// ...
};
class Car : public Proc<Car, Position, Size, Color> {/*...*/};

c++ template interdependant types

I am trying to write simple hashtable in c++. My hashtable implementation template looks like this:
template<class k, class v, class h<k>, class e<k> >
class my_hash {
};
where
k = class type for key
v = class type for value
h = class type for hash fn
e = class type for equality fn
I have defined class h like this
template<class k>
class h {
};
I would specialize above template for different k types e.g. int, string etc. What I want to do is whenever I invoke my_hash template with k,it should automatically pick up the
h<k>
as the hash function type.For this to happen how do I define template ?
If I define it like I have shown it above, g++ gives compiler error saying h is not a template ? Could somebody please help me with this ?
I think what you need is called template template parameter and it is this:
template<class k, class v, template<typename> class h, template<typename> class e>
class my_hash
{
//then here you can intantiate the template template parameter as
h<k> hobj;
e<k> eobj;
//...
};
Now you can pass class template (which takes one type argument) as the third and fourth template argument to the above class template. Look for template template parameter in your book, or online, know more about it. You can start from here:
What are some uses of template template parameters in C++?
C++ Common Knowledge: Template Template Parameters
Hope that helps.
You can certainly use template template parameters, but your intended use case - where the template types are closely related - is a common one, that is idiomatically solved with traits.
With hash keys, usually the key type is closely related with the hash function and equality function. With traits you can do something like this silly example:
template <class T> struct key_hash_traits;
template <>
struct key_hash_traits<int>
{
typedef int key_type;
static size_t hash(int k) { return k*k / 42; }
};
template <class T, class V>
struct my_non_functioning_hash_table
{
void insert(T::key_type t, V v)
{
if (T::hash(t) == 13)
{
std::cout << "hello world\n";
}
}
};
int main()
{
int k = 256;
my_non_functioning_hash_table<key_hash_traits<int>, float> h;
h.insert(k, 3.14);
}
See how with key_hash_traits, all the interrelated types (key, hash func) are placed together, which is nice, and the definition of my_non_functioning_hash_table is simpler too as it only needs to refer to the trait. This example does assume you'll only ever have one hash func per key type, but you can easily modify that. I hope you get the general idea.
For more reading on traits, see these links:
Traits: a new and useful template technique
Traits: The else-if-then of Types

Is there a way to bind a template<template> parameter?

Context
I have a custom comparator that takes another comparator and applies an additional check:
template <template <typename> class Comparator, typename T>
struct SoftOrder : public std::binary_function<T, T, bool> {
bool operator()(const T lhs, const T rhs) const {
return Comparator<T>()(lhs, rhs) && AnotherCheck();
}
};
I have a second class that accepts a comparator, e.g.:
template <template <typename> class Comparator>
class Processor { ... };
It is easy to instantiate a Processor with a standard comparator (e.g. std::less) like so:
Processor<std::less> processor1;
Processor<std::greater> processor2;
However it is not so easy to instantiate with SoftOrder as the compiler correctly complains about the missing second template argument:
Processor<SoftOrder<std::less> > processor3; // <-- Fails to compile
Current Solutions
I have come up with a few solutions prior to posting this question.
First Solution - Lots of Derived Classes
template <typename T>
struct SoftOrderLessThan : public SoftOrder<std::less, T> {};
template <typename T>
struct SoftOrderGreaterThan : public SoftOrder<std::greater, T> {};
The main drawback of this solution is the need to create a new struct every time a new variant is required, e.g.:
template <typename T>
struct SoftOrderLessThan : public SoftOrder<std::less, T> {}; // Never used after the next line.
Processor<SoftOrderLessThan> processor3;
Second Solution - A very specific bind class
template <template <typename> class Comparator>
struct BindToSoftOrder {
template <typename T>
struct type : public SoftOrder<Comparator, T> {};
};
This is slightly better in that we don't need to create the intermediate classes explicitly:
Processor<BindToSoftOrder<std::less>::type> processor3;
The downside is the requirement of a class specialised for this situation which cannot really be generalised by making SoftOrder a template parameter on BindToSoftOrder as this would make it a template<template<template>>> which is not permitted by the standard.
Third Solution - C++11 template aliases
template <typename T>
using SoftOrderLessThan = SoftOrder<std::less, T>;
Nicer than the first option in that it doesn't require the introduction of new classes, however still requires littering the code with this extra code that is only used in passing onwards to another template class:
template <typename T>
using SoftOrderLessThan = SoftOrder<std::less, T>; // Never used again
Processor<SoftOrderLessThan> processor3;
Finally, the question
Is there a generic way to bind my custom comparator to a specific comparator in the following manner?
Processor<SomeCoolMetaTemplateBind<SoftOrder, std::less>::type> processor3;
I believe if all of the template parameters were simple types I could just do something like Processor<boost::mpl::bind<SoftOrder, std::less> >, but the presence of the template type in the template parameter list prevents this from occurring.
An ideal solution would involve C++03, but am happy to hear C++11 solutions as well.
If it's not possible, I hope at least the question was interesting.
Seems like this would work:
template <
template <template <typename> class,class> class U,
template <typename> class X
>
struct SomeCoolMetaTemplateBind {
template <typename T>
struct type : public U<X,T> {
};
};