[C++, templates] Conversion ctor voor TT<non-const T>

Pagina: 1
Acties:

Onderwerpen

Vraag


Acties:
  • 0 Henk 'm!

  • Mijzelf
  • Registratie: September 2004
  • Niet online
Is er een keywoord om 'non-const' te definiëren?

Concreet, gegeven de volgende template
C++:
1
2
3
4
5
6
template<typename T> class TTemplate
{
public:
    TTemplate(){}
    TTemplate( const TTemplate<T> & ){}
};
Voor de schoonheid van het programma zou een template van een const type ook een copy constructor met een non-const template moeten accepteren. Het is ook normaal dat non-const objecten zonder meer naar const objecten converteren.
Maar hier niet:
C++:
1
2
3
TTemplate<char> y;
TTemplate<char> x = y;
TTemplate<const char> z = y;
$ g++ Test.cpp
Test.cpp:12:27: error: conversion from 'TTemplate<char>' to non-scalar type 'TTemplate<const char>' requested
 TTemplate<const char> z = y;
Nu denk ik dat een non-const keyword dit zou oplossen:
C++:
1
2
3
4
5
6
7
template<typename T> class TTemplate
{
public:
    TTemplate(){}
    TTemplate( const TTemplate<T> & ){}
    TTemplate( const TTemplate<non-const T> & ){}
};
Wat vul ik in voor non-const?

Beste antwoord (via Mijzelf op 26-09-2017 12:57)


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Behalve dan dat je dan in de problemen komt als T al non-const is (ODR violation, want TTemplate<T>(const TTemplate<T>&) is al gedefinieerd). Je zal er een member template van moeten maken (kan vrij simpel door geen een default dummy template parameter te definieren)

De vraag is of je wel echt alleen const wil solven, en niet ook volatile, of wellicht convertable types in het algemeen.

[ Voor 35% gewijzigd door .oisyn op 26-09-2017 11:20 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Alle reacties


Acties:
  • 0 Henk 'm!

  • ThomasG
  • Registratie: Juni 2006
  • Laatst online: 15:52
Je kunt daar std::remove_const voor gebruiken.

Acties:
  • Beste antwoord
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Behalve dan dat je dan in de problemen komt als T al non-const is (ODR violation, want TTemplate<T>(const TTemplate<T>&) is al gedefinieerd). Je zal er een member template van moeten maken (kan vrij simpel door geen een default dummy template parameter te definieren)

De vraag is of je wel echt alleen const wil solven, en niet ook volatile, of wellicht convertable types in het algemeen.

[ Voor 35% gewijzigd door .oisyn op 26-09-2017 11:20 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Mijzelf
  • Registratie: September 2004
  • Niet online
Dat is een leuke. Nooit eerder van gehoord.
.oisyn schreef op dinsdag 26 september 2017 @ 11:07:
Behalve dan dat je dan in de problemen komt als T al non-const is (ODR violation, want TTemplate<T>(const TTemplate<T>&) is al gedefinieerd).
Inderdaad. Compiler error.
Je zal er een member template van moeten maken
Deze code compileert:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename T> class TTemplate
{
protected:
    T *pT;
public:
    TTemplate(): pT(0){}
    template<typename Y> TTemplate( const TTemplate<Y> &t ):
        pT( t.Get() )
    {}
    T *Get() const { return pT; }
};

TTemplate<char> y;
TTemplate<char> x = y;
TTemplate<const char> z = y;
De vraag is of je wel echt alleen const wil solven, en niet ook volatile, of wellicht convertable types in het algemeen.
Met deze code pikt hij inderdaad ook
C++:
1
2
TTemplate<char> y;
TTemplate<volatile char> a = y;

Ik zie zo gauw geen nadelen hiervan. Binnen mijn huidige project heb ik er ook geen voordeel van (wie gebruikt volatile in templates?).
Dit kan natuurlijk wel allerlei impliciete casts opleveren. Zitten daar nadelen aan?

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Het mooie daarvan is dat hij ook dit accepteert:
C++:
1
2
3
class Base { };
class Derived : public Base { };
TTemplate<Base> b = TTemplate<Derived>();


Het jammere is dat dit een vreemde error geeft:
C++:
1
TTemplate<int> a = TTemplate<float>();


Dat zou je zo kunnen fixen:
C++:
1
2
template<class Y, class U = std::enable_if_t<std::is_convertible_v<Y*,T*>, void>>
TTemplate(const TTemplate<Y>&t)


Of als je compiler dat nog niet slikt:
C++:
1
2
template<class Y>
TTemplate(const TTemplate<Y>&t, typename std::enable_if<std::is_convertible<Y*,T*>::value, std::nullptr_t>::type = nullptr)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Mijzelf
  • Registratie: September 2004
  • Niet online
.oisyn schreef op dinsdag 26 september 2017 @ 12:38:
Het jammere is dat dit een vreemde error geeft:
C++:
1
TTemplate<int> a = TTemplate<float>();
Dat valt toch wel mee?
$ g++ Test.cpp
Test.cpp: In instantiation of 'TTemplate<T>::TTemplate(const TTemplate<Y>&) [with Y = float; T = int]':
Test.cpp:17:37:   required from here
Test.cpp:9:14: error: cannot convert 'float*' to 'int*' in initialization
  pT( t.Get() )

Exact dezelfde melding als ik krijg met
C++:
1
int *a = (float *)0;

Dit lijkt mij gewenst gedrag.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

In dit voorbeeld wel. In de werkelijkheid kan die foutmelding een stuk dieper zitten, waardoor de fout niet direct evident is. Feitelijk klopt de error ook niet - het is namelijk niet zo dat je een float* niet naar een int* mag converteren, maar eigenlijk is de error dat je een TTemplate<float> niet naar een TTempalte<int> mag converteren :). Die pointer conversion is slechs een implementatiedetail van je klasse.

[ Voor 9% gewijzigd door .oisyn op 26-09-2017 13:36 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1