Newsgroup: it.comp.lang.c++
Titolo: Riconoscere se un field di una classe è un  tipo parametrico di una classe template

Riconoscere se un filed di una classe è ad esempio un tipo è intero,
è cosa ben nota:
template <typename T>
struct is_int
{
	enum { res = false };
};
template <>
struct is_int<int>
{
	enum { res = true };
};
template <typename ClassType, typename FieldType>
bool isInt(FieldType ClassType::* ptom)
{
	return (is_int<FieldType>::res);
}
template <typename T>
class Holder
{
public:
	T holded;
};
int main()
{
	if (isInt(&Holder<int>::holded)) cout << "is int" << endl;
	else cout << "isn't int" << endl;
}
Ora la domanda delicata, forse insensata, e forse indecibile è la seguente.
E' possibile determinare se quell'attributo "holded" era definito come 
tipo parametrico di una classe template!?
Vorrei cioè poter avere una funzione simile alla seguente:
isTemplate(&Holder<int>::holded) -> deve ritornare true...
--
Fabio

 tipo parametrico di una classe template!?
Alla domanda non saprei rispondere con certezza (anche se ho l'impressione
che la risposta sia no), comunque faccio notare che il participio passato di
"to hold" è "held".
--
Cingar
--------------------------------
Inviato via 
http://arianna.libero.it/usenet/

 
;-) ...grazie!!!
Mi scuso per l'innioranza... :-)

Non saprei, ma dai un'occhiata qui:
http://boost.org/libs/type_traits/index.html
-- 
int

#include <cassert>
template <typename TypeT, template <typename> class Templ, typename
ArgT>
bool isTempl(TypeT Templ<ArgT>::*member)
{
  return false;
}
template <typename TypeT, template <typename> class Templ>
bool isTempl(TypeT Templ<TypeT>::*member)
{
  return true;
}
template <typename T> struct C
{
  T t;
  int i;
};
int main()
{
  assert(isTempl(&C<char>::t));
  assert(isTempl(&C<double>::i));
}
Dal che, tra l'altro, si evince che e' possibile eliminare la struct
is_int dall'esempio originale.
Ciao,
Nicola


Grazie mille...
In parte funziona, ma cosa succederebbe nel caso in cui
la struct C è istanziata con un parametro di tipo int?
A quel punto isTempl ritornerebbe in entrambi i casi true,
sia per C<int>::t che per C<int>::i.

#include <cassert>
template <typename TypeT, template <typename> class Templ, typename
ArgT>
bool isTempl(TypeT Templ<ArgT>::*member)
{
  return false;
}
template <typename TypeT, template <typename> class Templ>
bool isTempl(TypeT Templ<TypeT>::*member)
{
  return true;
}
template <typename T> struct C
{
  T t;
  int i;
};
int main()
{
  assert(isTempl(&C<char>::t));
  assert(isTempl(&C<double>::i));
}
Dal che, tra l'altro, si evince che e' possibile eliminare la struct


 }
Cos'è  template <typename> class Templ  ? 8-|
-- 
int

Nicola Musatti wrote:

Bellissimo esempio! Ma li usi veramente nel lavoro di tutti i giorni 
questi costrutti? Se sě, puoi fare un esempio di situazione in quali 
tornano comodi?
-- 
Sě d'accordo "Free Mandela", "Free Valpreda" e tutti gli altri, ma Free 
anche Fitti Fattis!

 
template template parameter.
Serve per passare una classe template come parametro ad un'altra classe 
o funzione template.
--
Fabio.

Non frequentemente, ma qualche volta si. In fondo il meccanismo di base
e' relativamente semplice, ovvero l'utilizzo della specializzazione o
dell'overload per identificare e fattorizzare in un punto specifico del
codice la scelta tra un'insieme di varianti.
Tra parentesi questo "idiom" e' utile indipendentemente dai template.
L'ho usato recentemente per poter utilizzare indifferentemente due
classi distinte per la rappresentazione di valori monetari, una
"legacy", che si porta dietro il valore sia in lire che in euro, e
l'altra che rappresenta solo gli euro.
Scrivendo
ValutaSingola getEuro(ValutaSingola vs) { return vs; }
ValutaSingola getEuro(ValutaDoppia vd) { return vd.getEuro(); }
Ho potuto collegare con facilita' due sottosistemi che usavano
convenzioni diverse.
Ciao,
Nicola

 
Basta fare cosi:
#include<iostream>
template<class TypeOfMember,
	 template <class> class Template,
	 class OtherType>
bool memberAsTemplate(TypeOfMember Template<OtherType>::*member)
{
   return false;
}
template<class TypeOfMember,
	 template <class> class Template>
bool memberAsTemplate(TypeOfMember Template<TypeOfMember>::*member)
{
   return true;
}
struct ifTemplate {};
template<class T>
class Test
{
public:
   int num;
   T something;
};
int main()
{
   std::cerr << "Test::num has type as template: " << std::boolalpha << 
memberAsTemplate(&Test<int>::num) << '.' << std::endl;
   std::cerr << "Test::something has type as template: " << 
std::boolalpha << memberAsTemplate(&Test<int>::something) << '.' << 
std::endl;
   std::cerr << "---" << std::endl;
   std::cerr << "Test::num is template: " << std::boolalpha << 
memberAsTemplate(&Test<ifTemplate>::num) << '.' << std::endl;
   std::cerr << "Test::something is template: " << std::boolalpha << 
memberAsTemplate(&Test<ifTemplate>::something) << '.' << std::endl;
   return 0;
}
Output:
Test::num has type as template: true.
Test::something has type as template: true.
---
Test::num is template: false.
Test::something is template: true.
HTH.
Ciao!
sakurai.

Non so se e' una soluzione valida, portabile... vedete voi :)
// Questa serve solo per dimostrazione dell'esempio
struct Y {
    operator char() {};
    operator double() {};
};
// struct di cui si vuole sapere se i membri sono template o no
template <class T>
struct X {
 T t;
 int i;
 Y y;
};
template <template <typename> class Classe>
 void IsTemplate(char Classe<char>::*c, double Classe<double>::*d) {};
int main() {
 IsTemplate(&X<char>::t, &X<double>::t); // Compila
 IsTemplate(&X<char>::i, &X<double>::i); // Non compila
 IsTemplate(&X<char>::y, &X<double>::y); // Non compila
 return 0;
}
La funzione puo' essere invocata solo se t e' un template (almeno credo :P).
Infatti ho volutamente messo 2 argomenti alla funzione in modo da passare 2
tipi radicalmente diversi (char, double) i quali possono essere accettati
contemporaneamente solo da un template visto che se non sbaglio per le per
le funzioni template il compilatore non esegue conversioni di tipo
implicite. Nemmeno se per il tipo di t e' definito un operatore di
conversione verso char e uno verso double (vedi y) tale conversione avviene.
Ciao

 
:-) thanks...


Bitte!
Ciliegina:
#define IS_TEMPLATE(aClass,a) memberAsTemplate(&aClass<ifTemplate>::a )
;-)
ciao!
sakurai.


ARRGGGH!!!
Funzionava tanto bene...
Ma mi crea problemi passare quell'ifTemplate alle classi template...
;-(

 ;-(
cosa intendi?


Il tipo parametrico deve implementare certe funzionalità, quindi non 
posso passargli una classe vuota come ifTemplate, altrimenti il 
compilatore si lamenta.
E' colpa mia che ho tagliato troppe cose per postare un esempio più 
comprensibile...
Ovvero. la classe Holder dell'esempio utilizza attributi del tipo T che 
gli viene passato.
Ora l'ho adattata per risolvere il problema, ma ne è uscito fuori un 
altro... disperazione!!

 ;-(
Ma se il membro non e' un template deve restituire necessariamente false
oppure puo' anche dare errore di compilazione? Cioe' a te serve saperlo a
run time o solo in fase di progettazione del codice? Nel secondo caso,
potresti dare un'occhiata al mio post in questo thread e dirmi in quali casi
esso non va bene?
Grazie

 HTH.
Scusa l'OT ma vedo questo acronimo (credo) un sacco di volte e mi chiedo
cosa significhi, potresti soddisfare tale mia curiosita? :)
Ciao

 cosa significhi, potresti soddisfare tale mia curiosita? :)
Hope This Helps..


 
Ora come ora l'userei a runtime quel risultato. Cmq se č calcolato a 
compile time non guasta.
Se non č template non voglio che dia errore il compilatore.
Finalmente so cosa significa HTH... :-)

 
http://bovis.gyuvet.ch/3dict/312usene.htm
Grazie
Ciao

 Finalmente so cosa significa HTH... :-)
Basta chiedere :P

 Perche' a compile time se non da errore come ti avverte che non e' template?
Con un enum o con un typedef (metaprogrammazione statica).
Oppure qualche trucco con sizeof.

 Oppure qualche trucco con sizeof.
Idem :P
In ogni caso, la compilazione o va a buon fine (con qualche warning
eventualemente) o segnala errori (e con questo intendo che l'errore possa
anche essere scovato dal linker). Cosa puo' accadere a parte questi casi?
Grazie

 
template <int n>
struct IsPari
{
	enum { res = n%2 ? 0 : 1 };
};
Era questa la domanda?

 Era questa la domanda?
Si ma... per valutare il valore di res devi eseguirlo... cioe'
l'informazione su n la ottieni a run-time. Io chiedevo su come facesse il
compilatore a compile-time ad avvertirti senza dare un'errore o un warning.
Ciao

 
Non necessariamente...
template <bool b,typename Then, typename Else>
struct If;
template <typename Then, typename Else>
struct If<true, Then, Else>
{
	typedef Then Result;
};
template <typename Then, typename Else>
struct If<false, Then, Else>
{
	typedef Else Result;
};
If<IsPari<1234>, ..., ...>::Result

 If<IsPari<1234>, ..., ...>::Result
Umh... puoi completarlo e renderlo funzionante? :)

 
:-X
#include <iostream>
using namespace std;
template <bool b,typename Then, typename Else>
struct If;
template <typename Then, typename Else>
struct If<true, Then, Else>
{
	typedef Then Result;
};
template <typename Then, typename Else>
struct If<false, Then, Else>
{
	typedef Else Result;
};
template <int n>
struct IsPari
{
	enum { res = n%2 ? 0 : 1 };
};
struct Pari
{
	static void apply()
	{
		cout << "Pari" << endl;
	}
};
struct NonPari
{
	static void apply()
	{
		cout << "NonPari" << endl;
	}
};
int main()
{
	If<IsPari<1234>::res, Pari, NonPari>::Result::apply();
	system("pause");
	return 0;
}

 If<IsPari<1234>::res, Pari, NonPari>::Result::apply();
[cut]
Come temevo, non ci siamo capiti :D
Vedo di riassumere:
Fabio: Se non è template non voglio che dia errore il compilatore.
Noixe: A compile-time se non da errore come ti avverte che non e' template?
Fabio: Con un enum o con un typedef (metaprogrammazione statica).
Noixe: Umh... mi fai un esempio? (Pari e Dispari)
E siamo arrivati al post attuale.
La domanda cruciale era: A compile-time se non da errore come ti avverte che
non e' template?
Il tuo codice dice "Pari" o "NonPari" solo se lo esegui quindi a run-time.
Ora, non so io cosa significa compile-time? Sei tu che hai capito un'altra
cosa?
Ciao :)

 
Ah... ok ;-)
Sai gli STATIC_CHECK!?
Creano errori ad hoc...
E quello avviene solo con errori o warning a compile time...
Non c'eravamo capiti...
Sorry...

Sorry...
:)

 
Dai un'occhiata al file static_check.h su loki-lib.
La trovi su sourceforge.
--
Fabio.

 Controlli statici? Che tipo di errori creano?
Più che controlli sono assert.
In linea di massima funziona così:
template <bool> struct STATIC_ASSERT_T; // un bel template
template <>     struct STATIC_ASSERT_T<true> {};
// ... lo specializzo solo per "true" ma non per "false"
#define STATIC_ASSERT( B ) sizeof( STATIC_ASSERT_T<B> );
// una macro che valuta la dimensione del tipo, la quale sarà valida
// solo per B == true dal momento che con false sarebbe incompleto e non
// può essere calcolato dal sizeof
void f()
{
        STATIC_ASSERT( 1 + 1 == 2 );  // tutto bene
        STATIC_ASSERT( 1 + 1 == 11 ); // il compilatore ti avverte che
        // oltre questa riga non può andare avanti perchè
        // STATIC_ASSERT_T<false> è un tipo non completo e non può farne
        // il sizeof
}
Ma ogni compilatore/piattaforma sembra avere le sue "cose", per cui vedi
se da te funziona, sennò usa/guarda il file static_assert.hpp di boost,
che forse è meglio.
Saluti
-- 
int