Recursive Compound structure - c++

I have a class that looks something like this:
template<class KeyType, class... Types>
class BasicCompound
{
public:
using mapped_type = std::variant
<
ValueWrapper<BasicCompound>
, ValueWrapper<Types>...
>;
using key_type = KeyType;
// Accessors for retreiving and modifying content
// ...
private:
std::map<key_type, mapped_type> m_content;
};
ValueWrapper decides to put the content either inline or in a std::unique_ptr. Would it be possible with a similar interface, possibly through some kind of proxy, to make the recursiveness optional? By optional I mean that the user should not automatically get the possibility to store the BasicCompound inside itself, but rather specify it in the list of types.
What I have thought of:
A using directive does not work. A new type cannot be defined in it self, and a predeclaration of a following typedef is not allowed.
Adding a bool to the list of types, and use std::conditional_t for mapped_type. However, if the user wants to store an X<BasicCompound>, this approach fails.
Inject mapped_type from outside. Then I cannot hide the use of the ValueWrapper thing.
Using inheritance over a typdef like
struct MyCompound : BasicCompound<std::string, MyCompound, int> {};
This works but then the structure is not strictly recursive, as MyCompound now is a different type from BasicCompound. Maybe a CRTP-like approach could solve that problem, but then the inner compound type must be treated differently than the other types.

You can't have use a specialization of a class template as one of the template arguments of that specialization; there's no way to write it, and its name would be infinitely long. You can, however, use a wrapper to hold the recursive type:
template<class> class MaybeRecursive;
template<class T>
struct Wrapper {
using type=T;
};
struct MRWrapper {
using type=MaybeRecursive<MRWrapper>;
};
template<class T>
struct MaybeRecursive {
using type=typename T::type;
type *child;
};
void f() {
int x;
MaybeRecursive<Wrapper<int>> nonrec={&x};
MRWrapper::type rec={&rec};
}
MRWrapper can be made a class template to provide additional template arguments to MaybeRecursive.

Related

specialize std::hash<T> for dependent types

I have defined this template class structure:
template<typename T> struct Outer {
struct Inner { /* ...some stuff... */ };
};
I want to put Inner objects into an unordered_map (actually, not directly them but containers of them, so the approach of specifying hashing object directly on template parameters for unordered_map is not a great idea), thus I wanted to specialize the hash class for these items.
This will not work, because the compiler cannot match Outer<T>::Inner with the type specified when instantiating hash:
namespace std {
template<typename T> struct hash<typename Outer<T>::Inner > {
size_t operator ()( typename Outer<T>::Inner const & obj )
{ /* ...some stuff... */ }
};
};
Does anyone know a solution to this?
You're obviously right that this will not work because the compiler cannot match a template specialization that is based on such a dependent type (e.g., Inner could be a nested typedef, then how would the compiler be able to tell the difference between that type coming from the nested typedef in Outer, versus from elsewhere? It can't, it's impossible to tell).
There are a number of solutions.
First, you could move the Inner class to the outside of the Outer class (and make them friends, if needed). You can also move it into a "detail" namespace or hide it in a number of other ways depending on your context. It is not uncommon for people to avoid such nested "Inner" classes because they can cause a number of problems like this and some older compilers even have problems accepting such nested classes at all. It's generally better practice to just move those nested classes out of the Outer class. In terms of actual code, you do this:
template <typename T>
struct Outer; // forward-decl.
namespace detail {
template <typename T>
struct Outer_Inner {
friend class Outer<T>; // Optional
// ....
};
};
template <typename T>
struct Outer {
typedef detail::Outer_Inner<T> Inner;
friend class detail::Outer_Inner<T>; // Optional
// ...
};
namespace std {
template<typename T>
struct hash< detail::Outer_Inner<T> > {
// ..
};
};
Another solution is to define your own hashing class that you can give to the unordered_set. Like this:
template <typename T>
struct Outer {
struct Inner {
//..
};
struct InnerHash {
typedef Inner argument_type;
typedef std::size_t result_type;
result_type operator()(argument_type const& s) const {
return /* some hashing code */;
};
};
// ...
// An example unordered-set member:
std::unordered_set<Inner, InnerHash> m_set;
};
And finally, there is yet another solution I can think of that, like the first solution, has the advantage of specializing the std::hash class template. However, this solution is a bit convoluted, it involves wrapping your Inner class into an outside class template, like this:
template <typename T>
struct InnerWrapper {
typedef typename Outer<T>::Inner value_type;
value_type data;
};
and then creating the specialization std::hash< InnerWrapper<T> >. This solution really only has the advantage of being non-intrusive on the existing implementation of the Outer class, but creating an unordered_map in this case means that the map must contain (directly or indirectly) InnerWrapper objects instead of storing the Inner objects directly. Also, you should notice that this solution can be mixed with the first solution by having some of the functionality of Inner that is more tightly integrated with Outer implemented in a nested class, and having the more "public" functionality of Inner implemented in the outside class, thus avoiding the friendship relationship and allowing tighter Outer-Inner integration, while leaving a clean user-facing class to access Inner's functionalities.

Storing return type and arguments type of a method

Is it possible to determine and store the return type of SomeMethod using decltype (if it is the best way to do it, otherwise what is the best way to do it) at compile time ?
Is it also possible to use the same tool to store a type list of the arguments of SomeMethod ?
This idea behind that is to make them easily accessible from outside the class using getters.
class SomeClass
{
public:
typedef [???] ProcRetType;
typedef [???] ProcArgTypeList;
public:
SomeClass() { }
~SomeClass() noexcept { }
SomeType SomeMethod( SomeType1 arg1, SomeType2 arg2 ) { }
// Data members
private:
};
For the return type, you can just use decltype:
typedef decltype(SomeMethod(std::declval<SomeType1>(), std::declval<SomeType2>())) ProcRetType;
For the parameters, you'll need a helper trait. That can also be used for the return type, like this:
template <class Func>
struct Helper;
template <class T, class R, class... Arg>
struct Helper<R (T::*)(Arg...)>
{
typedef std::tuple<Arg...> ArgTypes;
typedef R ReturnType;
};
And then use it like this:
typedef Helper<decltype(&SomeClass::SomeMethod)>::ReturnType ProcRetType;
typedef Helper<decltype(&SomeClass::SomeMethod)>::ArgTypes ProcArgTypeList;
I'm using std::tuple to represent the type list - other representations are also possible, such as Boost.MPL.
You might need to provide a few other partial specialisations of Helper to account for const functions (and possibly volatile and old-style variadic functions as well, if that applies to you).
You can represent types with std::type_info objects (constructed via the typeid operator) and store them with std::type_index.
As an example you can do:
auto ret_type = std::type_index(typeid(ProcRetType));
to store ProcRetType in a variable.
And due to the fact that std::type_index is both CopyConstructible and CopyAssignable, you can also store them in containers like std::vector. For example:
std::vector<std::type_index> vec;
vec.emplace_back(typeid(int));
vec.emplace_back(typeid(double));
// ...

Prevent ADL on template parameters

I currently have a class template that takes a series of types. Each type may need to be instantiated with the class, itself. What I currently have is something like this:
template <typename... Types>
struct TypeList; // Not defined
struct Placeholder; // Not defined
template <typename Types, typename AnotherType = Default>
class MyClass
{
// ...
};
You can then use it like this:
typedef MyClass<TypeList<Container1<Placeholder>, Container2<std::string,
Placeholder>, OtherType>, OptionalType> MyTypedef;
MyTypedef my_object;
MyClass will replace appearances of Placeholder with itself, use the resulting types, and all is well.
The problem occurs when I try to do something like either of these:
MyTypedef *my_ptr = &my_object;
my_free_function(my_object);
Both of these cause a compiler error, because the compiler tries to instantiate Container1<Placeholder> and Container2<std::string, Placeholder> to do argument dependent lookup (ADL), and this instantiation with Placeholder, itself, fails.
I know it is possible to avoid ADL by doing, e.g.,
MyTypedef *my_ptr = std::addressof(my_object);
(my_free_function)(my_object);
However, I don't want to burden the user of MyClass with having to constantly suppress ADL. Is there another, straightforward way to have the user provide a list of types without those types being used for ADL?
Okay, I got everything working. The trick was to use a dependent type instead of using a template, directly. My final solution was to define TypeList as follows:
template <typename... Types>
struct TypeList
{
private:
struct Holder
{
private:
typedef TypeList<Types...> InnerTypeList;
template <typename Types, typename AnotherType>
friend class MyClass;
};
public:
typedef Holder type;
};
Then, the users of MyClass can do
typedef MyClass<TypeList<Container1<Placeholder>, Container2<std::string,
Placeholder>::type, OtherType>, OptionalType> MyTypedef;
MyTypedef my_object;
Note the addition of '::type'
Finally, in MyClass, I replaced
typedef typename SubstituteType<Types, Placeholder, MyClass>::type InternalTypeList;
with
typedef typename SubstituteType<Types::InnerTypeList, Placeholder, MyClass>::type
InternalTypeList;
giving me the same type for InternalTypeList as before.
Because the dependent type Holder has no template parameters of it's own, the compiler doesn't have to instantiate the Placeholder types for ADL purposes, and everything works properly.

cleaning up heavy use of template parameters

I have a set of classes in a logging framework used by project A and B. I am refactoring the framework so it can be used in project B and C. The refactoring mainly consists of giving everything template parameters: project A might run on an embedded device with poor/no STL implemenatation, while B and C just run on a pc, but B is single threaded while C uses multithreading.
This works well, but results in what seems to me an awfull lot of template parameters and a rather ugly typedef mess. I need like 20 lines to typedef all classes I'm going to use, and there are also lots of classes taking a template parameter they do not use themselves, but is needed to be able to typedef another class they do use (which is not per se a bad thing, but in the end everything starts to llok really complicated). Another problem is that when I want to add some functionality to class A and it requires adding a container, class A needs an extra template paramater. As a result, all other classes seeing/using class A suddenly also need that extra parameter leading to a domino effect.
Slightly exaggerated example:
template< class string, class map, class mutex >
class MessageDestination
{
typedef Message< string, map > message_type;
virtual void Eat( const message_type& ) = 0;
}
template< class string, class map, class stream >
class MessageFormatter
{
typedef Message< string, map > message_type;
virtual void Format( const message_type&, stream& ) = 0;
}
template< class string, class map, class containerA,
template< class, class > containerB, template< class, class > class queue, class allocator >
class ThreadedMessageAcceptor
{
typedef Message< string, map > message_type;
typedef MessageDestination< string, map > destination_type;
typedef containerB< destination_type, allocator > destinations_type;
typedef queue< message_type, allocator > messages_type;
};
I can think of some techniques to clean this up, but I'm having a hard time deciding what one or which combination to use. StackOverFlow, your help will be appreciated!
Here's the first solution I thought of, joining parameters together into the type they'll eventually form:
template< class message, class mutex >
class MessageDestination
{
virtual void Eat( const message& ) = 0;
}
This makes it simpler, but doesn't it at the same time it kind of hides what message actually is? Suppose a user wants to provide an implementation, he does not directly see that message has to use a certain string type etc.
Another technique I thougt about, but cannot recall having seen before somwhere which makes it look suspicious, is simply defining everything in a single struct and passing that as single template parameter to everything:
struct MyTemplateParameters
{
typedef std::string string;
typedef std::map map;
typedef std::queue queue;
typedef LightMutex mutex;
template< class A, class B >
struct DefineContainerB
{
typedef containerB< A, B >::type;
}
//....
};
template< class parameters >
class MessageDestination
{
typedef Message< parameters > message_type;
virtual void Eat( const message_type& ) = 0;
};
template< class parameters >
class ThreadedMessageAcceptor
{
typedef Message< parameters > message_type;
typedef MessageDestination< parameters > destination_type;
typedef parameters::DefineContainerB< destination_type, parameters::allocator >::type destinations_type;
};
This is nice as it allows specifying everything at one single point, and the typedefs to all classes will all be class XXX< MyTemplateParameters >, but again, it gives me an uneasy feeling. Is there a reason for this?
The “other” technique is very common in C++. The parameters class is usually called a “trait class”.
This is the way to go (why does it give you an uneasy feeling?). It is used pervasively in the Boost libraries and other C++ libraries. Even the standard library uses it, e.g. in the std::basic_string class.
An equally well-established alternative are metafunctions. At its most basic, a metafunction is a “function” that operates on types rather than objects. So where a function takes value arguments and returns a value, a metafunctions takes template arguments and “returns” a type:
template <typename T>
struct identity {
typedef T type;
};
The metafunction is used (“invoked”) like a normal type definition.
typedef identity<int>::type mytype; // or
identity<int>::type x;
Not very useful in this case. But consider the following common metafunction:
template <typename T>
struct remove_const {
typedef T type;
};
template <typename T>
struct remove_const<T const> {
typedef T type;
};
This can be used to make an arbitrary type (in particular a template argument) non-const. This is actually a type I’m currently using in a project: I have a class that accepts both const and non-const types and offers appropriate interfaces. However, internally I need to store a non-const reference. Simple, I just use the following code in my class:
typename remove_const<T>::type& _reference;
(The typename is required because T is a template argument and that makes remove_const<T>::type a dependent type. Your above example code is actually omitting quite a few required typenames – it won’t compile on several modern compilers!)
Now, how to apply this to your problem?
Create two empty marker types that specify whether your types are used on an embedded device or on a compliant compiler:
struct Embedded { };
struct Compliant { };
Now you can define your classes in terms of these, e.g.:
template<typename Spec>
class ThreadedMessageAcceptor
{
typedef Message< Spec > message_type;
typedef MessageDestination< Spec > destination_type;
typedef typename Allocator< destination_type, Spec >::type allocator_type;
typedef typename ContainerB< destination_type, allocator_type, Spec >::type destinations_type;
};
Here, Spec will be either Compliant or Embedded. So to use it on a standards compliant compiler, write:
ThreadedMessageAcceptor<Compliant> x;
The class uses the following metafunctions:
template <typename T, typename Spec>
struct Allocator { };
template <typename T, typename Alloc, typename Spec>
struct ContainerB { };
You need to remember to specialize them appropriately for your target specifications, e.g.:
template <typename T>
struct Allocator<T, Compliant> {
typedef std::allocator<T> type;
};
template <typename T, typename Alloc>
struct ContainerB<T, Alloc, Compliant> {
typedef std::vector<T, Alloc> type;
};
This already shows that a metafunction may have arbitrarily many arguments besides the Spec (which I’ve put last on a whim – but its placement should be consistent).
To be sure, this is more code than when using a single trait class but it has lower cohesion, logically separates concerns and is easier to reuse.

C++: Default values for template arguments other than the last ones?

I have my templated container class that looks like this:
template<
class KeyType,
class ValueType,
class KeyCompareFunctor = AnObnoxiouslyLongSequenceOfCharacters<KeyType>,
class ValueCompareFunctor = AnObnoxiouslyLongSequenceOfCharacters<ValueType>
>
class MyClass
{
[...]
}
Which means that when I instantiate an object of this class, I can do it several different ways:
MyClass<MyKeyType, MyValueType> myObject;
MyClass<MyKeyType, MyValueType, MyCustomKeyCompareFunctor> myObject;
MyClass<MyKeyType, MyValueType, MyCustomKeyCompareFunctor, MyCustomValueCompareFunctor> myObject;
Those are all good. The problem comes when I want to instantiate a MyClass that uses a non-default version of the ValueCompareFunctor argument, but I still want to use the default value of the KeyCompareFunctor argument. Then I have to write this:
MyClass<MyKeyType, MyValueType, AnObnoxiouslyLongSequenceOfCharacters<MyKeyType>, MyCustomValueCompareFunctor> myObject;
It would be much more convenient if I could somehow omit the third argument and just write this:
MyClass<KeyType, ValueType, MyCustomValueCompareFunctor> myObject;
Since the MyCustomValueCompareFunctor works only on objects of type MyValueType and not on objects of type MyKeyType, it seems like the compiler could at least theoretically work out what I meant here.
Is there a way to do this in C++?
In general, both in templates and functions or methods, C++ lets you use default for (and thereby omit) only trailing parameters -- no way out.
I recommend a template or macro to shorten AnObnoxiouslyLongSequenceOfCharacters<MyKeyType> to Foo<MyKeyType> -- not perfect, but better than nothing.
No. The closest you can come is to allow users to specify some sentinel type - like void - meaning "use default value here", and use template metamagic inside your class to typedef the real default if void was given to you. But this probably isn't a good idea from readability point of view.
Boost parameters and Boost graph named parameters are efforts towards naming parameters for template functions/methods. They give the opportunity to provide arguments in whichever order you prefer. Some arguments may be optional, with default values.
The same approach may be applied to template arguments. Instead of having N template arguments + P optional ones, create your class with N+1 template arguments. The last one will hold "named" parameters which can be omitted.
This answer is not complete yet, but i hope it's a good start !
An alternative option is to use Traits classes:
template <class KeyType>
class KeyTraits
{
typedef AnObnoxiouslyLongSequenceOfCharacters<KeyType> Compare;
};
template <class ValueType>
class ValueTraits
{
typedef AnObnoxiouslyLongSequenceOfCharacters<ValueType> Compare;
};
template<class KeyType class ValueType>
class MyClass
{
typedef KeyTraits<KeyType>::Compare KeyCompareFunctor;
typedef ValueTraits<ValueType>::Compare KeyCompareFunctor;
};
Then if you have a type which needs a different comparison function for Key's, then you'd explicitly specialize the KeyTraits type for that case. Here's an example where we change it for int:
template <>
class KeyTraits<int>
{
typedef SpecialCompareForInt Cmopare;
};
There is another option, which uses inheritance and which works like the following. For the last two arguments, it uses a class that inherits virtually from a class that has two member templates, that can be used to generate the needed types. Because the inheritance is virtual, the typedefs it declares are shared among the inheritance as seen below.
template<class KeyType,
class ValueType,
class Pol1 = DefaultArgument,
class Pol2 = DefaultArgument>
class MyClass {
typedef use_policies<Pol1, Pol2> policies;
typedef KeyType key_type;
typedef ValueType value_type;
typedef typename policies::
template apply_key_compare<KeyType>::type
key_compare;
typedef typename policies::
template apply_value_compare<ValueType>::type
value_compare;
};
Now, have a default argument that you use, which has typedefs for the default arguments you want provide. The member templates will be parameterized by the key and value types
struct VirtualRoot {
template<typename KeyType>
struct apply_key_compare {
typedef AnObnoxiouslyLongSequenceOfCharacters<KeyType>
type;
};
template<typename ValueType>
struct apply_value_compare {
typedef AnObnoxiouslyLongSequenceOfCharacters<ValueType>
type;
};
};
struct DefaultArgument : virtual VirtualRoot { };
template<typename T> struct KeyCompareIs : virtual VirtualRoot {
template<typename KeyType>
struct apply_key_compare {
typedef T type;
};
};
template<typename T> struct ValueCompareIs : virtual VirtualRoot {
template<typename ValueType>
struct apply_value_compare {
typedef T type;
};
};
Now, use_policies will derive from all the template arguments. Where a derived class of VirtualRoot hides a member from the base, that member of the derived class is dominant over the member of the base, and will be used, even though the base-class member can be reached by other path in the inheritance tree.
Note that you don't pay for the virtual inheritance, because you never create an object of type use_policies. You only use virtual inheritance to make use of the dominance rule.
template<typename B, int>
struct Inherit : B { };
template<class Pol1, class Pol2>
struct use_policies : Inherit<Pol1, 1>, Inherit<Pol2, 2>
{ };
Because we potentially derive from the same class more than once, we use a class template Inherit: Inheriting the same class directly twice is forbidden. But inheriting it indirectly is allowed. You can now use this all like the following:
MyClass<int, float> m;
MyClass<float, double, ValueCompareIs< less<double> > > m;