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> {
};
};
Related
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
Here is MCVE (uncompilable) :-
#include <iostream>
#include <type_traits>
//-- library ---
template<class T,template<class>class Slot,class DefaultType>
class GetType{
template <typename C> static Slot<T> check( Slot<T>*);
template <typename> static DefaultType check(...);
public: using type=decltype(check<T>());
};
template<class T,template<class>class Slot,class DefaultType>
using X = typename GetType<T,Slot,DefaultType>::type;
Here is its usage :-
//--- user defined ---
class B {public: using MyType=int;};
class C{};
template<class T> using SlotCustom = typename T::MyType;
int main(){
using ShouldInt=X< B ,SlotCustom ,long>; //B::Mytype =int , result:int
using ShouldLong=X< C ,SlotCustom ,long>;//C::Mytype not exist, result:long
std::cout<< std::is_same_v<ShouldInt, int> <<std::cout; //should true
std::cout<< std::is_same_v<ShouldLong, long> <<std::cout; //should true
}
My objective is to create a library typedef X< Param1 ,SlotCustom ,DefaultType> that means as the following pseudo code:-
if ( SlotCustom<Param1> has meaning) return "SlotCustom<Param1>" ;
else return "DefaultType"; //i.e. by default
How to do it?
Here is a similar question.
The main difference is that X<T> there can be only a bool, and many things are hardcoded.
I am new to template specialization. The solution might be obvious, but I can't find it.
If I understand your question correctly, then your approach can be made to work, for example
template <template <class> class Slot, class DefaultType>
struct GetType
{
template <typename T>
static Slot<T>&& deduce(T&&);
static DefaultType&& deduce(...);
template <typename T>
using type = std::remove_reference_t<decltype(deduce(std::declval<T>()))>;
};
template <class T, template <class> class Slot, class DefaultType>
using X = typename GetType<Slot, DefaultType>::template type<T>;
live demo here
The problem with your initial attempt was that the call to your check function in the expression for decltype() needed some argument for overload resolution to take place so that the SFINAE magic can happen. My example above relies on std::declval to introduce a dummy argument of the necessary type. Also, note that my helper functions use references rather than passing the types by value directly. This is so that it also works with types that are not copyable. Note that there will be problems if Slot<T> or the DefaultType are reference types themselves. One would have to, e.g., introduce additional wrapper types to deal with that…
Alternatively, you could use partial class template specialization to pick the correct type, for example:
template <class T, template <class> class Slot, class DefaultType, typename = void>
struct GetType
{
using type = DefaultType;
};
template <class T, template <class> class Slot, class DefaultType>
struct GetType<T, Slot, DefaultType, std::void_t<Slot<T>>>
{
using type = Slot<T>;
};
template <class T, template <class> class Slot, class DefaultType>
using X = typename GetType<T, Slot, DefaultType>::type;
live demo here
The trick here lies in the use of the last template parameter with default argument void. Due to the way the matching of partial class template specializations works (see, e.g., this answer), the specialization will only be picked if Slot<T> is a valid type. Note that above solution requires C++17. If you have to stay within C++14 (which you probably don't, given that your own example relies on C++17), you can, e.g., provide your own implementation of void_t (as explained here):
template <typename... T> struct make_void { using type = void; };
template <typename... T> using void_t = typename make_void<T...>::type;
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
I wrote an abstract container template class that should define numeric operators (unary + and -, binary +, - and *) if it make sens for the template parameter (that is, if it is a numeric type).
Then, I would like to apply those numeric operations on containers of containers of numeric values (and on containers of containers of containers of numeric values, and so on).
I wrote the following code. The (A) marker shows how I tried to solve the recursive specialization problem.
template <typename T>
struct is_numeric : public std::is_arithmetic<T>{};
template <typename T> /* (A) */
struct is_numeric<GenericContainer<T>> : public std::is_arithmetic<T>{};
/* Classic generic container for non-numeric base types */
template <typename T, bool isNumeric=false>
class BaseContainer : public GenericContainer<T> {};
/* Numeric container: +,-,* operations for numeric base types */
template <typename T>
class BaseContainer<T, true> : public NumericContainer<T> {};
/* Arithmetic base types should map on numeric containers */
template <typename T>
class Container : public BaseContainer<T, is_numeric<T>::value> {};
Then, in a test program, I have the following assertions:
/* Vector inherits from Container */
typedef Vector<int, 3> V3D;
ASSERT(is_numeric<int>::value); /* # => OK */
ASSERT(is_numeric<double>::value); /* # => OK */
ASSERT(is_numeric<V3D>::value); /* # => FAIL */
The two firsts assertions work as expected
Your solution fails for a very specific reason: a template type parameter specialization will match only the exact type, and not any derived type.
If you wish for derived types to also match, you need switch gears and use another strategy. In the age of constexpr switching to functions will let you use overloading resolution to your advantage (as one strategy among others):
// Basis
constexpr bool is_numeric_impl(...) { return false; }
template <typename T>
constexpr bool is_numeric(T const& t) { return is_numeric_impl(&t); }
// Specializations
template <typename T,
typename = std::enable_if<std::is_arithmetic<T>::value>::type>
constexpr bool is_numeric_impl(T const*) { return true; }
template <typename T>
constexpr bool is_numeric_impl(GenericContainer<T> const*) {
return is_numeric((T const*)nullptr);
}
The main benefit being that this solution is open-ended so that other people may reuse the same traits and add specializations; because it uses a white-list.
Boost's enable_if and type traits allow tricks like you need:
template <class T, class Enable = void>
struct is_numeric : public std::is_arithmetic<T> {};
template <class T>
struct is_numeric<T, typename enable_if<is_base_of<GenericContainer<T>, T> >::type>
: public std::is_arithmetic<T> {};
The solution employs SFINAE principle to compile the second version of is_numeric when the template parameter meets the criteria inside enable_if. Notice that the syntax of is_base_of is is_base_of<Base, Derived>. There is more explanation in Boost's enable_if documentation.
Since the relationships in your case are even more complicated, as David Rodriguez kindly mentioned, you should probably make it a bit differently:
template <template <class> class U, class T>
struct is_numeric<U<T>, typename enable_if<is_base_of<GenericContainer<T>, U<T> > >::type>
: public std::is_arithmetic<T> {};
And if you cannot use the libraries themselves, you can always use them as inspiration :)
Did you try :
template <typename T>
struct is_numeric : public std::is_arithmetic<T>{};
template <template<class...> class Container, typename T, typename... Rest>
struct is_numeric<Container<T, Rest...>> : public is_numeric<T>{};
Seems to work for me.
You need to define the is_numeric trait for each container, you cannot just use the base definition.
template <typename T, size_t N>
struct is_numeric< Vector<T,N> > : is_numeric< GenericContainer<T> > // *
{};
Also note that the definition of the is_numeric should be similar the one in the comment, not the one in the question. That is, you want to define is_numeric for a container in terms of whether the nested type is numeric or not (so that you can peel off the different layers).
I have a class template, expecting some other template as a parameter:
template<
class Key,
template <typename K,template <typename T> class Allocator> class Policy
>
class container {
Policy<Key,Allocator>* _policy;
//some code here
};
and usually i use it with the policy class like this:
template <class Key,template <typename T> class Allocator> class policy {
//some code
};
but what if i have to pass additional template parameter to policy class? Something like:
template <time_t Age,class Key,template <typename T> class Allocator> class policy_3 {
//some code
};
What can i do, to allow users of that class, pass the Age paratemeter without touching others? For example:
typedef container<key_type,policy_3<100500> > containerWithAge;
You have two options: binding, and rebinding.
In binding, you adapt the ternary policy into a binary one, as expected by the template-template parameter Policy:
template <typename Key, template <typename T> class Allocator>
struct policy_3_100500 : ternary_policy<100500,Key,Allocator> {};
and use policy_3_100500 instead of policy_3<100500>.
To be closer to the syntax you're shooting for, you can use a nested class:
template <time_t Age>
struct policy_3 {
template <typename Key, template <typename T> class Allocator>
struct type : ternary_policy<Age,Key,Allocator> {};
};
and use policy_3<100500>::type instead of policy_3<100500>.
The only way to get exactly the syntax you want is to move the ::type into the class using the policy. That's the second option: rebinding (this is also used in std::allocator, btw). In this case, you pass the Policy as a normal template parameter, and assume a template metafunction, say bind, to exist:
template <time_t Age>
struct policy_3 {
template <typename Key, template <typename T> class Allocator>
struct bind : ternary_policy<Age,Key,Allocator> {};
};
While structually identical to the second option, the difference lies in who calls bind: In the first option (binding), it's the user of the policy class (by passing policy<100500>::type explicitly). Here, it's the class using the policy:
template <typename Key, typename Policy>
struct container {
typename Policy::template bind<Key,std::allocator<Key>> * _policy;
// ...
}:
As a general note, Policy classes are not usually passed as template-template arguments, but as normal template arguments (precisely because they may have a varying number of arguments themselves). The classes using the policy then assume a certain inner structure (typedefs, functions, meta functions, constants) to be present in the policy, of which bind is just an example.