Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Template Generierung explizit erlauben/verbieten

4 views
Skip to first unread message

Helmut Zeisel

unread,
Sep 10, 2009, 5:06:12 AM9/10/09
to
Ich möchte gerne die Generierung von Template Code je nach Typ
explizit erlauben oder verbieten. Im Prinzip ist mir klar, wie das
geht. Ein Beispiel, wie es funktioniert, steht im Anhang.

Frage: gibt es dafür (benannte?) Quasi-Standards/Pattern, damit ich
nicht lange erklären muss, was ich mir dabei gedacht habe?

Helmut

======== Codebeispiel ==========

struct disallowed {};
struct allowed
{
typedef int allowed_t;
};

template<typename T> class mytraits: public disallowed {};
template<> class mytraits<double>: public allowed {};

class myclass
{
public:
template<typename T> operator T()
{
typedef typename mytraits<T>::allowed_t allowed_t;
T result=0;
return result;
}
private:
};

static myclass d;
static double c1=d; // OK
static int c2=d; // Compile fails

SG

unread,
Sep 12, 2009, 2:53:42 AM9/12/09
to
On 10 Sep., 11:06, Helmut Zeisel <zei200...@liwest.at> wrote:
> ======== Codebeispiel ==========
>
> struct disallowed {};
> struct allowed
> {
> typedef int allowed_t;
>
> };
>
> template<typename T> class mytraits: public disallowed {};
> template<> class mytraits<double>: public allowed {};
>
> class myclass
> {
> public:
>     template<typename T> operator T()
>     {
>       typedef typename mytraits<T>::allowed_t allowed_t;
>       T result=0;
>       return result;
>     }
> private:
>
> };
>
> static myclass d;
> static double c1=d; // OK
> static int c2=d;    // Compile fails
> ==================

>
> Frage: gibt es dafür (benannte?) Quasi-Standards/Pattern, damit ich
> nicht lange erklären muss, was ich mir dabei gedacht habe?

Das ist so eine Art "statische Assertion". Du kannst es aber
vielleicht noch kompakter und leserlicher aufschreiben, indem Du
Boost.TypeTraits, Boost.StaticAssert und/oder
Boost.ConceptCheckLibrary benutzt. Beispiel:

template<typename T> operator T()
{

BOOST_STATIC_ASSERT(
(boost::is_same<T,double>::value) );
T result=0;
return result;
}

Natürlich macht es weniger Sinn, für nur genau einen Typen überhaupt
ein Template zu erstellen. Die Sache mit einer statischen Assertion
hat auch einen Haken: operator T() für ein belibiges T ungleich double
kann immer noch Teil des "overload sets" sein, so dass in einem Fall
wie diesen:

void foo(void*);
void foo(double);

void bar(myclass & o) {
foo(o); // Mehrdeutig. Welches foo?
}

der Aufruf mehrdeutig ist, obwohl sich nur der Operator für T=double
fehlerfrei instanziieren lässt. Einen solchen Fall kann man eigentlich
mit "SFINAE" gut lösen. Allerdings ist SFINAE bei
Konvertierungsoperatoren nicht anwendbar. Zumindest wüsste ich nicht,
wie. Du findest zu dem Thema wahrscheinlich relativ schnell
Informationen, wenn Du nach "SFINAE" und "enable_if" suchst.

Gruß,
SG

Raymond Haeb

unread,
Sep 12, 2009, 10:25:02 AM9/12/09
to
Helmut Zeisel schrieb:
> Ich m�chte gerne die Generierung von Template Code je nach Typ

> explizit erlauben oder verbieten. Im Prinzip ist mir klar, wie das
> geht. Ein Beispiel, wie es funktioniert, steht im Anhang.
>
> Frage: gibt es daf�r (benannte?) Quasi-Standards/Pattern, damit ich
> nicht lange erkl�ren muss, was ich mir dabei gedacht habe?

boost::enable_if
http://www.boost.org/doc/libs/1_40_0/libs/utility/enable_if.html


Raymond

Helmut Zeisel

unread,
Sep 14, 2009, 2:36:58 AM9/14/09
to
On Sep 12, 4:25 pm, Raymond Haeb <ray.h...@gmx.de> wrote:

> boost::enable_ifhttp://www.boost.org/doc/libs/1_40_0/libs/utility/enable_if.html

Danke, das ist das, wonach ich gefragt habe, aber siehe auch meine
Antwort an SG.

Helmut

Helmut Zeisel

unread,
Sep 14, 2009, 2:36:01 AM9/14/09
to
On Sep 12, 8:53 am, SG <s.gesem...@gmail.com> wrote:

> Das ist so eine Art "statische Assertion". Du kannst es aber
> vielleicht noch kompakter und leserlicher aufschreiben, indem Du
> Boost.TypeTraits, Boost.StaticAssert und/oder
> Boost.ConceptCheckLibrary benutzt. Beispiel:
>
>     template<typename T> operator T()
>     {
>        BOOST_STATIC_ASSERT(
>           (boost::is_same<T,double>::value) );
>        T result=0;
>        return result;
>     }

Ja, so in der Art habe ich es gemeint.

> Natürlich macht es weniger Sinn, für nur genau einen Typen überhaupt
> ein Template zu erstellen.

Klar, ich denke da an Anwendungen wie z.B. dass nur Konvertierung zu
Gleitkommazahlen erlaubt sein soll.

> Die Sache mit einer statischen Assertion
> hat auch einen Haken: operator T() für ein belibiges T ungleich double
> kann immer noch Teil des "overload sets" sein, so dass in einem Fall
> wie diesen:
>
>     void foo(void*);
>     void foo(double);
>
>     void bar(myclass & o) {
>        foo(o);  // Mehrdeutig. Welches foo?
>     }
>
> der Aufruf mehrdeutig ist, obwohl sich nur der Operator für T=double
> fehlerfrei instanziieren lässt.

Das will ich eigentlich auch vermeiden.

> Einen solchen Fall kann man eigentlich
> mit "SFINAE" gut lösen. Allerdings ist SFINAE bei
> Konvertierungsoperatoren nicht anwendbar. Zumindest wüsste ich nicht,
> wie.

:-(

Dann bleibt wohl doch nur, die Interfaces explizit zu spezifizieren
und die Templates nur für die Implementierung zu nehmen, z.B.

operator double(){return convert_to<double>(*this);}

Helmut

Scooser

unread,
Sep 24, 2009, 3:21:48 AM9/24/09
to
Hallo,
sofern dir Typen reichen für die es sinnvolle numeric_limits gibt
kannst Du folgendes Versuchen:

template<typename T, bool isExact> class Convertor;
template<typename T> class Convertor<T, false>
{
public:
T operator() (const YourType& source) const
{
// code for converting a YourType to a float/double
}
};

template<typename T> void convert(const YourType& source, T& target)
{
MyConvertor<T, numeric_limits<T>::is_exact> convertor;
target = convertor (source);
}

- Scooser

Helmut Zeisel

unread,
Sep 28, 2009, 8:41:41 AM9/28/09
to
On Sep 24, 9:21 am, Scooser <michael.kn...@googlemail.com> wrote:
> Hallo,
> sofern dir Typen reichen für die es sinnvolle numeric_limits gibt
> kannst Du folgendes Versuchen:

Danke, ja. Wenn ich eine eigene Template Funktion verwende, duerfte
das mit SFINAE machbar sein.
Eigentlich will ich aber mit dem "normalen" Conversion Operator
auskommen.

Helmut

SG

unread,
Sep 29, 2009, 10:09:42 AM9/29/09
to
On 28 Sep., 14:41, Helmut Zeisel wrote:
>
> Danke, ja. Wenn ich eine eigene Template Funktion verwende, duerfte
> das mit SFINAE machbar sein.
> Eigentlich will ich aber mit dem "normalen" Conversion Operator
> auskommen.

Es gibt aber einen leichten Trost. In C++0x wird es möglich sein.

#include <type_traits>

#define REQUIRES(...) ,class=typename \
std::enable_if<(__VA_ARGS__)>::type

class foo {
int rep;
public:
foo(int x) : rep(x) {}

template<typename T
REQURIES( std::is_convertible<int,T>::value )
>
operator T() const {
return rep;
}
};

Gruß,
SG

Markus Schaaf

unread,
Sep 29, 2009, 3:07:07 PM9/29/09
to
SG schrieb:

> template<typename T
> REQURIES( std::is_convertible<int,T>::value )

^^^^^^^
kannst Du weglassen

SG

unread,
Sep 30, 2009, 2:34:09 AM9/30/09
to
On 29 Sep., 21:07, Markus Schaaf <msch...@elaboris.de> wrote:
> SG schrieb:

>
> > #include <type_traits>
> >
> > #define REQUIRES(...) ,class=typename \
> > std::enable_if<(__VA_ARGS__)>::type
> >
> > [...]

Nicht, dass ich wüsste. std::enable_if erwartet als ersten Template-
Parameter einen boolschen Wert. Es ist also mit boost::enable_if_c
vergleichbar. Man kann natürlich das Makro anders definieren, zB so

template<bool... B> struct and_c : std::true_type {};
template<bool... B> struct and_c<true,B...> : and_c<B...> {};
template<bool... B> struct and_c<false,B...> : std::false_type{};
template<class... Cond> struct and_ : and_c<Cond::value...> {};

template<bool... B> struct or_c : std::false_type {};
template<bool... B> struct or_c<true,B...> : std::true_type{};
template<bool... B> struct or_c<false,B...> : or_c<B...>{};
template<class... Cond> struct or_ : or_c<Cond::value...> {};

template<class Cond> struct not_
: std::integral_constant<bool,(! Cond::value)> {};

#define REQUIRES(...) ,class=typename \
std::enable_if<and_<(__VA_ARGS__)>::value>::type

Allerdings ist die Version nur von Vorteil, wenn man Bedingungen durch
UND Verknüpfen will. Wenn man ODER-Verknüpfung und Negation braucht,
wir es schnell unleserlich:

template<typename T, typename U
REQUIRES( is_convertible<T,int> ,
or_< is_same<U,double>, is_same<U,float> > )
>
// bedeutet:
// is_convertible<T,int>::value &&
// (is_same<U,double>::value || is_same<U,float>::value)

Gruß,
SG

Helmut Zeisel

unread,
Sep 30, 2009, 6:27:34 AM9/30/09
to
On Sep 29, 4:09 pm, SG <s.gesem...@gmail.com> wrote:

> Es gibt aber einen leichten Trost. In C++0x wird es möglich sein.
>
>   #include <type_traits>
>
>   #define REQUIRES(...) ,class=typename \
>     std::enable_if<(__VA_ARGS__)>::type
>
>   class foo {
>     int rep;
>   public:
>     foo(int x) : rep(x) {}
>
>     template<typename T
>       REQURIES( std::is_convertible<int,T>::value )
>     >
>     operator T() const {
>       return rep;
>     }
>   };

Funktioniert das intern nicht mit SFINAE (und versagt somit beim
Conversion-Operator)?

Helmut

SG

unread,
Sep 30, 2009, 1:55:54 PM9/30/09
to
On 30 Sep., 12:27, Helmut Zeisel wrote:

> On Sep 29, 4:09 pm, SG wrote:
>
> > Es gibt aber einen leichten Trost. In C++0x wird es möglich sein.
>
> >   #include <type_traits>
>
> >   #define REQUIRES(...) ,class=typename \
> >     std::enable_if<(__VA_ARGS__)>::type
>
> >   class foo {
> >     int rep;
> >   public:
> >     foo(int x) : rep(x) {}
>
> >     template<typename T
> >       REQURIES( std::is_convertible<int,T>::value )
> >     >
> >     operator T() const {
> >       return rep;
> >     }
> >   };
>
> Funktioniert das intern nicht mit SFINAE

Richtig.

> (und versagt somit beim
> Conversion-Operator)?

Nein. Es gibt keine Regel, die besagt, dass "SFINAE" bei
Konvertierungsoperatoren verboten sei. Bei C++03 lässt sich SFINAE
schlicht nicht anwenden, weil man das enable_if nirgends einsetzen
könnte -- weder als Teil des return-Typs noch als Typ eines Default-
Parameters. C++0x unterstützt aber Default-Template-Parameter für
Funktionstemplates. Damit sollte es gehen. Das enable_if taucht hier
nämlich als Teil des Default-Template-Parameters auf.

Gruß,
SG

Markus Schaaf

unread,
Sep 30, 2009, 4:25:14 PM9/30/09
to
SG schrieb:

> On 29 Sep., 21:07, Markus Schaaf <msch...@elaboris.de> wrote:
>> SG schrieb:
>>
>>> #include <type_traits>
>>>
>>> #define REQUIRES(...) ,class=typename \
>>> std::enable_if<(__VA_ARGS__)>::type
>>>
>>> [...]
>>>
>>> template<typename T
>>> REQURIES( std::is_convertible<int,T>::value )
>> ^^^^^^^
>> kannst Du weglassen
>
> Nicht, dass ich wüsste.

Ich habe an boost gedacht.

Helmut Zeisel

unread,
Oct 1, 2009, 6:41:57 AM10/1/09
to
On Sep 30, 7:55 pm, SG <s.gesem...@gmail.com> wrote:

> C++0x unterstützt aber Default-Template-Parameter für
> Funktionstemplates. Damit sollte es gehen. Das enable_if taucht hier
> nämlich als Teil des Default-Template-Parameters auf.

Hab's jetzt verstanden, danke

Helmut

0 new messages