[C++] Templated friends

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • SH4D3H
  • Registratie: Juni 2004
  • Laatst online: 27-02 23:46
Ik ben een beetje aan het experimenteren met templates en wil graag een friend gebruiken om de '+' & '-' te overloaden om het gedrag voor de template class vast te leggen.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <iostream>
using namespace std;

// Declare friends as templates
template <typename T> class Type;
template <typename T> Type<T> operator +(T arg1, Type<T> arg2);
template <typename T> Type<T> operator -(T arg1, Type<T> arg2);

template <typename T>
class Type
{
private:
    T x, y;
public:
    // Constructors
    Type() { };
    Type(T i, T j) { x = i; y = j; }
    
    // And use friends for the reverse: <T> + & - Type<T>
    friend Type<T> operator +(T arg1, Type<T> arg2);
    friend Type<T> operator -(T arg1, Type<T> arg2);
    
    // Send x & y to standard output
    void show();
};

template <typename T>
Type<T> operator +(T arg1, Type<T> arg2)
{
    Type<T> temp = arg2;
    temp.x = arg2.x + arg1;
    temp.y = arg2.y + arg1;
    return temp;
}

template <typename T>
Type<T> operator -(T arg1, Type<T> arg2)
{
    Type<T> temp = arg2;
    temp.x = arg2.x - arg1;
    temp.y = arg2.y - arg1;
    return temp;
}

template <typename T>
void Type<T>::show()
{
    cout << "X, Y: " << x << ", " << y << endl;
}

int main()
{
    Type<int> a(3, 4);
    Type<float> b(3.0, 5.4);
    Type<char> c('X', 'D');
    
    a.show();
    b.show();
    c.show();
    cout << endl;
    
    // a = a + 10; Dit werkt, maar is in deze testcase even weggelaten
    b = 5.0 + b; // ** Deze wil ik dus werkend krijgen. **
    // c = c + 1;
    
    // a.show();
    b.show();
    // c.show();
    
    return 0;
}


Deze code compileert met de volgende warnings:
warning: friend declaration ‘Type<T> operator+(T, Type<T>)’ declares a non-template function
note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
Als ik die suggestie toepas, compileert de code niet meer:
error: declaration of ‘operator+’ as non-function
error: expected ‘;’ before ‘<’ token
Bij het linken krijg ik, na het compileren zonder de extra <>:
(.text+0xae): undefined reference to `operator+(float, Type<float>)'
Op aanraden van deze FAQ heb ik de templated prototypes nog even voor de class definitie toegevoegd, maar dat mocht dus niet baten. De compiler denkt nog steeds dat het non-template functies zijn, maar zodra ik de blijkbaar benodigde <> toevoeg, werkt het helemaal niet meer.

Wat doe ik verkeerd?

PS: Ik gebruik g++.

Acties:
  • 0 Henk 'm!

  • Comp_Lex
  • Registratie: Juni 2005
  • Laatst online: 06:14
Ik heb weinig ervaring met templates, maar na een klein beetje googlen ben ik er achter gekomen dat dit
code:
1
friend Type<T> operator +(T arg1, Type<T> arg2);


misschien verandert moet worden in dit
code:
1
friend Type<T> operator + <> (T arg1, Type<T> arg2);

Acties:
  • 0 Henk 'm!

  • SH4D3H
  • Registratie: Juni 2004
  • Laatst online: 27-02 23:46
Dankjewel voor de input, helaas werkt dat (bij mij) dus niet.
Ik krijg dan, zoals vermeld, de volgende error:
error: declaration of ‘operator+’ as non-function
error: expected ‘;’ before ‘<’ token

Acties:
  • 0 Henk 'm!

  • xos
  • Registratie: Januari 2002
  • Laatst online: 12-09 12:41

xos

Waarom friend?

Vaak wordt de + operators in termen van de += operator geimplementeerd zodat deze 1 op 1 verband houden. Je class zou dan iets moeten worden als:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
template<class Type>
class MyType
{
public:
    explicit MyType(const Type& x) : x_(x)
    {}

    MyType<Type>& operator+=(const Type value)
    {
        x_ += value;
        return *this;
    }

    MyType<Type>& operator+=(const MyType<Type>& value)
    {
        x_ += value.x_;
        return *this;
    }

private:
    Type x_;
};


En de vrije functies:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
template<class Type>
MyType<Type> operator+(const Type lhs, const MyType<Type>& rhs)
{
    MyType<Type> result(rhs);
    result += lhs;
    return result;
}

template<class Type>
MyType<Type> operator+(const MyType<Type>& lhs, const MyType<Type>& rhs)
{
    MyType<Type> result(lhs);
    result.x_ += rhs.x_;
    return result;
}

template<class Type>
MyType<Type> operator+(const MyType<Type>& lhs, const Type rhs)
{
    MyType<Type> result(lhs);
    result += rhs;
    return result;
}

Hetzelfde geldt voor de - operator natuurlijk.

Ps: op regel 63 doe je 5.0 + b, 5.0 is by default een double terwijl je b als Type<float> hebt. Dit kan icm templates soms onverwachte compile problemen opleveren als types niet impliciet te converteren zijn naar elkaar.

Acties:
  • 0 Henk 'm!

  • SH4D3H
  • Registratie: Juni 2004
  • Laatst online: 27-02 23:46
Ik was in de veronderstelling (zo stelt mijn boek) dat member functies altijd de linker operand impliciet meekrijgen en je een situatie als de mijne oplost door middel van friend functies die beide operands wel expliciet meekrijgen.

Zowel op jouw manier (thanks! :D), als met een inline definitie werkt het echter wel precies zoals ik wil. Het blijft echter vreemd, ongeacht of mijn gebruik de beste manier is, dat "de" manier om een templated friend te gebruiken, bij mij niet werkt.

Edit: Blijkbaar werkt het wel bij als het niet om een operator... functie gaat.
C++:
1
friend MyType doStuff<>(MyType arg1, Type arg2);

Deze regel met een class & functieprototype aan het begin van het bestand compileren prima :?

[ Voor 20% gewijzigd door SH4D3H op 22-08-2010 19:37 ]


Acties:
  • 0 Henk 'm!

  • xos
  • Registratie: Januari 2002
  • Laatst online: 12-09 12:41

xos

Om een instantie van een functie template als vriend te definieren moet je de funtienaam voorzien van <>. Dit compileert wel (visual c++).

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
template<class Type>
class MyType
{
public:

    explicit MyType(const Type x) : x_(x)
    {}

    friend MyType<Type> operator+<>(const MyType<Type>& lhs, const MyType<Type>& rhs);
    friend MyType<Type> operator+<>(const MyType<Type>& lhs, const Type rhs);
    friend MyType<Type> operator+<>(const Type lhs, const MyType<Type>& rhs);
private:
    Type x_;
};

template<class Type>
MyType<Type> operator+(const Type lhs, const MyType<Type>& rhs)
{
    MyType<Type> result(rhs);
    result.x_ += lhs;
    return result;
}

template<class Type>
MyType<Type> operator+(const MyType<Type>& lhs, const Type rhs)
{
    MyType<Type> result(lhs);
    result.x_ += rhs;
    return result;
}

template<class Type>
MyType<Type> operator+(const MyType<Type>& lhs, const MyType<Type>& rhs)
{
    MyType<Type> result(lhs);
    result.x_ += rhs.x_;
    return result;
}

int main()
{
    MyType<double> a(1.0);
    MyType<double> b(1.5);
    MyType<double> c = 1.0 + b;
    MyType<double> d = a + 2.0;
}

Acties:
  • 0 Henk 'm!

  • Comp_Lex
  • Registratie: Juni 2005
  • Laatst online: 06:14
Ik ben in de war, was mijn reply dan wel oke of niet?

Acties:
  • 0 Henk 'm!

  • SH4D3H
  • Registratie: Juni 2004
  • Laatst online: 27-02 23:46
Ja, Comp_Lex, zie ook de link die ik gaf in de TS. Hier werkt het alleen niet.

Ook de code van xos compileert hier niet. (g++ 4.4.3)
Compilation failed.
test.cpp:9: error: declaration of ‘operator+’ as non-function
test.cpp:9: error: expected ‘;’ before ‘<’ token
test.cpp:10: error: declaration of ‘operator+’ as non-function
test.cpp:10: error: expected ‘;’ before ‘<’ token
test.cpp:11: error: declaration of ‘operator+’ as non-function
test.cpp:11: error: expected ‘;’ before ‘<’ token
test.cpp: In function ‘MyType<Type> operator+(Type, const MyType<Type>&) [with Type = double]’:
test.cpp:44: instantiated from here
test.cpp:13: error: ‘double MyType<double>::x_’ is private
test.cpp:20: error: within this context
test.cpp: In function ‘MyType<Type> operator+(const MyType<Type>&, Type) [with Type = double]’:
test.cpp:45: instantiated from here
test.cpp:13: error: ‘double MyType<double>::x_’ is private
test.cpp:28: error: within this context

Acties:
  • 0 Henk 'm!

  • Comp_Lex
  • Registratie: Juni 2005
  • Laatst online: 06:14
Ik heb hier een korte discussie gevonden over jouw probleem. Het schijnt dat je je code nog verder moet verbouwen voordat g++ het slikt.

Acties:
  • 0 Henk 'm!

  • SH4D3H
  • Registratie: Juni 2004
  • Laatst online: 27-02 23:46
Bedankt voor de link. Het lijkt erop dat een paar haakjes alle problemen oplost. Klinkt best logisch, maar was nog niet bij me opgekomen :+
Pagina: 1