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;
Related
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.
I have some code like this
class A : public b<T>
{
public:
typedef b<T> _baseclass; // why we need this declaration
};
What is the use of typedef inside the class?
Is the definition limited to this class only?
Shall we create this as static and use without crating an object of the class?
This member type will be available outside of the class definition too, which is convenient in template code. If you passed an A into a function template, or maybe some other classes that also have _baseclass member types, then you can use _baseclass to find out what the base is without needing to know exactly what the top-level type is.
Standard templates like std::vector and std::map have member types like value_type — these do not signify a base class but have a similar purpose, in that you can use value_type anywhere a container is used, no matter which container is used.
Swapping typedef to using (because I want to), here's an example:
// The class templates
template <typename T>
struct Base {};
struct A : Base<int>
{
using base_class = Base<int>;
};
struct B : Base<char>
{
using base_class = Base<char>;
};
struct C : Base<bool>
{
using base_class = Base<bool>;
};
// The example
template <typename T>
void foo()
{
// typename needed because base_class is a "dependent name"
// (just go with it)
typename T::base_class the_base;
// This line is to suppress "unused variable" warnings
(void)the_base;
}
int main()
{
foo<A>();
foo<B>();
foo<C>();
}
Though this particular program doesn't actually "do anything", it shows a function template foo that can "know" what the base class was in each case, without any further information about exactly what T is. And it'll work for any class to which you've added a base_class member type!
Suppose I have a derived class Derived. As well as taking template parameters, Derived is a derived class of Base, which in turn is templated on Derived.
The following illustrates an example of a working solution:
template <int i, typename T>
class Derived : public Base<Derived<i,T>>
{
};
template <typename DerivedType>
class Base
{
};
When the template argument list of Derived gets large, however, this becomes a pain, because coders who want to add derived classes to the library have to write the template arguments twice. Is there anyway of somehow automating this?
Here's what I'm after (the following doesn't compile because this doesn't exist yet, but it illustrates what I'm looking for):
template <int i, typename T>
class Derived : public Base<decltype(*this)>
{
};
template <typename DerivedType>
class Base
{
};
I'm open to an elegant macro solution (oxymoron perhaps?) if there is no way of achieving this with templates.
Use a traits class to contain the metadata rather than passing each item in the parameter list.
Here's what I do in a library I'm writing, soon to be open sourced.
First, there's the default traits class to cover the common case. I want to handle a range of common cases so it's also a template, but otherwise it could be a regular class. The parameterization is only what's convenient to the user, not the final detailed implementation parameterization, which instead comprises its contents.
template< typename rep_type, unsigned mantissa_values, rep_type fractional_cycles >
struct positive_logarithm_default_traits {
typedef double conv_basis;
static constexpr bool range_check = true;
typedef rep_type rep;
protected:
static constexpr rep max_rep = std::numeric_limits< rep >::max();
static constexpr rep unity_rep = mantissa_values * fractional_cycles;
// Another specialization could overflow to INFINITY and underflow to 0.
[[noreturn]] static rep underflow() { throw range_error( false ); }
[[noreturn]] static rep overflow() { throw range_error( true ); }
};
Then I define a metafunction to transform one instance of the class to another. It works within the traits class space, which can help compile time by eliminating instantiation of intermediate results if multiple metaprocessing transformations are strung together.
// The traits of a logarithm which represents the inverse of another logarithm.
template< typename traits >
struct inverse_traits : traits {
static constexpr decltype( traits::unity_rep ) unity_rep
= traits::max_rep - traits::unity_rep;
};
Although the traits class usually only contains compile-time data, I'll allow for runtime variation by inheriting from it. In such cases, the traits class may also want to access the state of the derived class. That's essentially CRTP. But, a given traits class might want to service several final derived classes with non-traits parameterization. So I make an additional class with runtime state accessible to the traits class, by static_cast< logarithm_state_base< traits > >( * this ) — this is functionally equivalent to CRTP but sidesteps a lot of metaprogramming complexity.
template< typename traits >
class logarithm_state_base : public traits {
protected:
typename traits::rep log_value;
};
Finally, the derived class provides the same convenient interface to the user as the default traits class interprets. Internally, though, it references all metadata through members inherited from the traits class.
If the user defines their own traits class, then the template parameters before typename traits_type (except mantissa_values) are vestigial and unused. An alias template could set them all to void to provide a solely traits-based user interface. Alternately, if I anticipated that traits usage would be more popular, I could do it the other way and let traits be the "native" interface and the itemized parameters be the convenience alias.
template<
typename rep, // Underlying representation type
unsigned mantissa_values, // # distinct values per power of 2
rep fractional_cycles = std::numeric_limits< rep >::max() / ( mantissa_values * 2 ) + 1,
typename traits_type = positive_logarithm_default_traits< rep, mantissa_values, fractional_cycles >
>
class static_positive_logarithm
: public logarithm_state_base< traits_type > {
static_assert ( std::is_unsigned< typename traits_type::rep >::value,
"Representation type must be unsigned." );
…
template <int i, typename X>
struct Derived
{
class T : public Base<T> { ... };
};
Derived<2, char>::T x;
I am trying to set the type of the member of a class, without passing it through template argument.
In details:
// Forward declaration:
class A;
class B;
class Base
{
};
template <class T>
class Derived : public Base
{
private:
T2 var;
};
where T could be either class A or class B.
What I would like to do is for Derived<A> T2 is int (for instance) and for Derived<B> T2 is double (for instance). I would like to avoid the following solution:
template <class T1, class T2>
class Derived : public Base
{
private:
T2 var;
};
I want to avoid this because for Derived<A> there could be various possible combinations for T2: Derived<A,int>, Derived<A,double>, ...
What I want is that the type of T2 is unique for the entire Derived<A>.
Any idea how to solve that ?
Update: The comments show that the original problem you are trying to solve is not completely explained in the question. I'll leave the original answer nevertheless at the bottom of this answer.
You cannot have two Derived<A> with different types T2 for the var member. In addition, a variable defined by the User can not influence the type of the member variable. Variable values are set at runtime, types are determined at compiletime.
To store a type somehow defined by the user, you will have either have to restrict the variable to a set of known types or use one type that contains a serialized version of the variable's content. The set of known types is often used in the context of databases, where the fields can have one of several predefined types (e.g. String, Integer, Boolean, Double). The type for the member variable then could be a Boost.Variant, restricted to C++ representations of that type. Another application of "user defined types" are where the user of your program has to somehow define the layout and interpretation of the type and its object, for example if your program is the interpreter of some scripting language. In that case again a Boost.Variant (or something similar) can be of use, or, since the value is probably some user provided input, just store the serialized value in a string and interpret it every time you have to deal with it.
Original answer:
This is usually done via template metaprogramming, in this case a type function (sometimes, depending on the context, part of a traits or policy class):
template <class T>
struct DerivedMemVarType {
typedef double type; //default
};
template<>
struct DerivedMemVarType<A> {
typedef int type;
};
And then:
template <class T>
class Derived : public Base
{
typedef typename DerivedMemVarType<T>::type T2;
private:
T2 var;
};
You can also leave out the default, so that any instantiation of Derived for a type that you have not mapped in your function will give a compile error:
template <class T>
struct DerivedMemVarType; //default is not defined
template<>
struct DerivedMemVarType<A> {
typedef int type;
};
template<>
struct DerivedMemVarType<B> {
typedef double type;
};
//...
Derived<C> dc; // ...template error mess....
// --> error: invalid use of incomplete type 'struct DerivedMemVarType<C>'
if you do not have any type specific function call, you can use something like...
class A;
class B;
class Base
{
};
template <class T>
class Derived : public Base
{
public:
Derived(T startVal):var(startVal){}
private:
T var;
};
template <typename T>
Derived<T> MakeDerived(T initValue)
{
return Derived<T>(initValue);
}
and now you can use it the following and the compiler should know what type you are passing to the function.
int initialValue = 0;
auto derived = MakeDerived(initialValue);
I think you can create a separate class that just holds a typedef which you then specialize and use in your Derived class.
template<typename T>
class VarType {
public:
typedef int TheType;
}
template <>
class VarType<B> {
public:
typedef double TheType;
};
template <typename T>
class Derived : public Base {
private:
typename VarType<T>::TheType var;
};
I'm trying to create a list of objects, where each object also stores 'ownership' - ie, it knows which list holds it.
In a non-template situation, it's straightforward:
class FooList; // forward declaration
class FooItem
{
public:
FooList *owner;
...
};
class FooList: private std::list<FooItem>
{
...
};
However, the list class is a template, based on the contained object type, and I'm struggling to work out how to specify this. I reckon the FooItem class now needs to be a template because the type of 'owner' can vary:
template <class E> class FooItem
{
public:
std::list<E> *owner;
};
template <class E> class FooList: private std::list<E>
{
...
};
But, now given my two templates, how can I define the new types I want? The snippet below is what I think I need, but it gives "error: Multiple declaration for BarItem".
class BarItem;
typedef FooList<BarItem> BarList;
typedef FooItem<BarList> BarItem;
EDIT:
Thanks to those who pointed out the issue of std::list<E> instead of std::list<FooItem<E> >
EDIT 2:
Renamed classes to Base, Derived, BaseList, DerivedList.
My real problem was the 'circular typedef'. After some more tinkering, I think this will do what I require. It creates a 'real' BarItem class rather than just a typedef, but seems to at least compile now.
template <class E> class BaseList; // forward declaration
template <class E> class Base
{
public:
BaseList< Base<E> > *owner;
};
template <class E> class BaseList: private std::list< E >
{
};
// typedef Base<BaseList<Derived> > Derived; //This won't compile, unsurprisingly.
class Derived : public Base < BaseList<Derived> > // Surprisingly, this seems to.
{
...
};
typedef BaseList<Derived> DerivedList;
Does this seem to make sense? Is it a common idiom or something horrible?
Are you sure you didn't want:
template <class E> class FooItem
{
public:
std::list< FooItem<E> > *owner; // owned by a list of FooItem<E>, not raw E
};
template <class E> class FooList: private std::list< FooItem<E> > // is a list of FooItem<E>, not raw E
{
...
};
The error you are getting is because you forward declare the class BarItem but later try to redefine that name using typedef. Not sure what you're trying to accomplish, but you'll need to introduce a third name. Maybe you meant:
class Bar;
typedef FooItem<Bar> BarItem;
typedef FooList<Bar> BarList;
EDIT: The new code you've posted certainly compiles, but seems very awkward (for one thing, the naming seems really confusing). Perhaps you should ask a new question with a more concrete example of why you think you need an 'item which is an item of lists of itself' and see if others can come up with a less awkward design.
Is that last set of typedef statements correct? You posted this:
class BarItem;
typedef FooList<BarItem> BarList;
typedef FooItem<BarList> BarItem;
It's somewhat recursive, right? The first statement says there's a class BarItem that exists elsewhere. The second statement says that the type FooList<BarItem> (a list of BarItem objects) can also be referred to as BarList. The third statement says that the type FooItem<BarList> can also be referred to as BarItem, but BarItem was already defined as a type by the class BarItem statement.
So you're saying that BarItem is a type all to itself (via the class statement), but you're also saying that BarItem is an alias for the type FooItem<BarList>. Hence the conflict.
If you just want to generalize your first approach to a templated FooItem class, it would look like this:
template <class E> class FooList; // forward declaration
template <class E> class FooItem
{
public:
FooList<E> *owner;
...
};
template <class E> class FooList: private std::list< FooItem<E> >
{
...
};
If that is not what you want I'm not sure what exactly you are attempting to do.