C ++: Standardverdier for andre enn de siste som malparametere?

stemmer
4

Jeg har min malbasert container klasse som ser slik ut:

template<
   class KeyType, 
   class ValueType, 
   class KeyCompareFunctor   = AnObnoxiouslyLongSequenceOfCharacters<KeyType>, 
   class ValueCompareFunctor = AnObnoxiouslyLongSequenceOfCharacters<ValueType> 
>
   class MyClass
   {
      [...]
   }

Hvilket betyr at når jeg instantiate et objekt av denne klassen, kan jeg gjøre det flere forskjellige måter:

MyClass<MyKeyType, MyValueType> myObject;
MyClass<MyKeyType, MyValueType, MyCustomKeyCompareFunctor> myObject;
MyClass<MyKeyType, MyValueType, MyCustomKeyCompareFunctor, MyCustomValueCompareFunctor> myObject;

De er alle gode. Problemet kommer når jeg ønsker å bruke et MyClass som bruker et ikke-standard versjon av ValueCompareFunctor argument, men jeg ønsker fortsatt å bruke standardverdien for KeyCompareFunctor argument. Så jeg må skrive dette:

MyClass<MyKeyType, MyValueType, AnObnoxiouslyLongSequenceOfCharacters<MyKeyType>, MyCustomValueCompareFunctor> myObject;

Det ville være mye mer praktisk hvis jeg kunne liksom utelate tredje argument og bare skrive dette:

MyClass<KeyType, ValueType, MyCustomValueCompareFunctor> myObject;

Siden MyCustomValueCompareFunctor fungerer kun på objekter av typen MyValueType og ikke på objekter av typen MyKeyType, virker det som kompilatoren kunne i det minste i teorien finne ut hva jeg mente her.

Er det en måte å gjøre dette i C ++?

Publisert på 01/08/2009 klokken 04:33
kilden bruker
På andre språk...                            


5 svar

stemmer
4

Nei. Det nærmeste du kan komme er å tillate brukere å spesifisere noen sentinel type - som void- som betyr "bruk standardverdien her", og bruke malen metamagic inne klassen til typedefden virkelige standard om voidble gitt til deg. Men dette er trolig ikke en god idé fra lesbarhet synspunkt.

Svarte 01/08/2009 kl. 04:39
kilden bruker

stemmer
5

Generelt, både maler og funksjoner eller metoder, kan C ++ du bruker standard for (og dermed utelate) bare følgende parametere - ingen vei ut.

Jeg anbefaler en mal eller makro å forkorte AnObnoxiouslyLongSequenceOfCharacters<MyKeyType>til Foo<MyKeyType>- ikke perfekt, men bedre enn ingenting.

Svarte 01/08/2009 kl. 04:39
kilden bruker

stemmer
3

Boost parametere og øke graf navngitte parametre er arbeidet mot å navngi parametere for sjablon funksjoner / metoder. De gir mulighet til å gi argumenter i hvilken rekkefølge du foretrekker. Noen argumenter kan være tilleggsutstyr, med standardverdier.

Den samme tilnærmingen kan brukes til malparametere. I stedet for at N malparametere + P valg seg, lage din klasse med N + 1 malparametere. Den siste vil holde "navngitte" parametere som kan utelates.

Dette svaret er ikke komplett ennå, men jeg håper det er en god start!

Svarte 01/08/2009 kl. 09:38
kilden bruker

stemmer
0

Et alternativ er å bruke Traits klasser:

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;
};

Så hvis du har en type som trenger en annen sammenligning funksjon for Key, så du vil eksplisitt rendyrke KeyTraits typen for den saken. Her er et eksempel der vi endre det for int:

template <>
class KeyTraits<int>
{
  typedef SpecialCompareForInt Cmopare;
};
Svarte 03/08/2009 kl. 10:29
kilden bruker

stemmer
0

Det er et annet alternativ, som bruker arv og som fungerer som følgende. For de to siste argumentene, bruker den en klasse som arver nesten fra en klasse som har to medlems maler, som kan brukes til å generere de nødvendige typer. Fordi arv er virtuelt, er typedefs det erklærer delt mellom arv som vist nedenfor.

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;
};

Nå har en standard argument som du bruker, som har typedefs for standard argumenter du vil gi. Medlems maler vil parametriseres av de viktigste og verdityper

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;
  };
};

use_policiesvil komme fra alle malparametere. Hvor en avledet klasse av VirtualRoothuder et medlem fra basen, som medlem av den avledede klassen er dominant over medlem av basen, og vil bli brukt, selv om baseklassen medlem kan nås med andre bane i arven treet.

Merk at du ikke betaler for den virtuelle arv, fordi du aldri lage et objekt av type use_policies. Du bruker bare virtuelle arv å gjøre bruk av dominans regelen.

template<typename B, int>
struct Inherit : B { };

template<class Pol1, class Pol2>
struct use_policies : Inherit<Pol1, 1>, Inherit<Pol2, 2>
{ };

Fordi vi potensielt stammer fra samme klasse mer enn én gang, bruker vi en klasse mal Inherit: Arve samme klasse direkte to ganger er forbudt. Men arve det indirekte er tillatt. Nå kan du bruke alt dette som følgende:

MyClass<int, float> m;
MyClass<float, double, ValueCompareIs< less<double> > > m;
Svarte 28/08/2009 kl. 23:48
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more