[C++] Template argument deduction

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Topicstarter
Puur uit interesse, volgende geval:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
template <typename T>
class A {
public:
    typedef std::shared_ptr<A<T> > Ptr;

    A() {}
    ~A() {}
};

template <typename U> void foo(typename A<U>::Ptr ptr) {
}

int main() {
    A<int>::Ptr a(new A<int>());
    foo(a);

   return 0;
}

Hier kan de compiler bij de call naar foo niet het template argument 'U' bepalen. Ik weet niet precies waarom niet, maar volgens mij gewoon omdat het niet in het lijstje met gevallen staat dat ondersteund moet worden. Kan me ook voorstellen dat omdat hij niks over Ptr weet totdat hij het type van U weet daar problemen onstaan oid.

Maar goed, je kan het oplossen door foo<int>(a); aan te roepen, maar dat vind ik omslachtig. Je kan het oplossen door foo() te declareren als foo(std::shared_ptr<A<U> >) maar dan raak je de mogelijkheid kwijt je pointer type te wijzigen. Je kan het met een templated typedef doen, maar dan heb je heb je een nieuwe compiler nodig... Wat is nou een goeie manier om dit op te lossen? Zo'n soort patroon zal toch wel vaker voorkomen?

Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Hier kan de compiler bij de call naar foo niet het template argument 'U' bepalen. Ik weet niet precies waarom niet, maar volgens mij gewoon omdat het niet in het lijstje met gevallen staat dat ondersteund moet worden
Het is vrij logisch. 'Ptr' is gewoon een typedef, en kan alles zijn. Om U te matchen zal hij alle mogelijke U af moeten gaan om te kijken of er een template instance is met een passende A<U>::Ptr. En dan kan het ook alleen als die uniek is, want wat als je nou probeert te matchen op std::vector<U>::size_type? Die is voor alle varianten van U meestal gelijk.
Wat is nou een goeie manier om dit op te lossen? Zo'n soort patroon zal toch wel vaker voorkomen?
Je kan het oplossen door een algemene foo<T>(T) te maken en dan met SFINAE kijken of T::element_type wel een A<U> is.

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!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Zo dus:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
template<class T> struct A
{
    typedef std::shared_ptr<A> ptr;
};

template<class T> struct is_instance_of_A
{
private:
    struct big { char c[2]; };
    static T* instance();
    template<class U> static char foo(A<U>*);
    static big foo(void*);

public:
    enum { value = sizeof(foo(instance())) == sizeof(char) };
};

template<class T>
typename std::enable_if<is_instance_of_A<typename T::element_type>::value, void>::type
foo(const T & t)
{
}

int main()
{
    A<int>::ptr p;
    int i;
    foo(p);
    foo(i);
}

[ Voor 6% gewijzigd door .oisyn op 20-08-2012 17:12 ]

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!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Topicstarter
Ok dat werkt idd. Bedankt :)

Ik vind het wel een beetje omslachtig ontwerp worden, dus ik denk dat ik het even om ga gooien. Maar wilde toch even weten wat hier nou de manier voor was.

Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Topicstarter
Ik snap nu ook al weer waarom het losse functies moesten zijn en geen members: vanwege het moeten returnen van een shared_ptr naar zichzelf (this). std::enable_shared_from_this met member functies is een betere oplossing denk ik.