2015-04-04 2 views
0

J'écris une méthode pour imprimer des espaces dans std::cout, je sais qu'il existe d'autres façons d'utiliser la bibliothèque standard pour atteindre le même objectif. Quoi qu'il en soit, j'ai utilisé un typedef pour stocker le nombre d'espaces et une surcharge de l'opérateur <<. Mais ma surcharge n'est pas appelée du tout parce que mon typedef est interprété comme un int non signé.C++ << surcharge de l'opérateur avec le même type

Alors, comment puis-je dire au compilateur d'appeler ma fonction à la place?

class MyClass { 
private: 
    typedef unsigned int space_type; 

public: 
    std::ostream& operator<< (std::ostream& _os, space_type _n_spaces) { 
    for (int _C = 0; _C < _n_spaces; _C++) 
     _os << " "; 
    return _os; 
    } 

    void PrintNumbers(char _a, char _b) { 
    space_type spaces = 5; 
    std::cout << _a << spaces << _b << std::endl; 
    } 
} 

int main() { 
    MyClass class_instance; 
    class_instance.PrintNumbers('K', 'X'); 

    std::cin.get(); 
    return 0; 
} 

Ceci est le résultat attendu:

K  X 

Ceci est la sortie I obtient:

K5X // 5 is interpreted as an unsigned int, so my overloaded function 
    // isn't called, instead is called the std overloading with unsigned int 
+0

Typedef ne crée pas de nouveau type, il crée simplement un alias de type existant. – kvorobiev

Répondre

1

Depuis que vous définissez space_type comme un alias (c.-à-typedef) et non un type, il ne se distingue pas de int, et le compilateur émettra une erreur si vous avez tenté de surcharger operator(std::ostream&, int).

Mais ce que vous faites est la définition d'un membre de la classe:

std::ostream& operator<< (std::ostream& _os, space_type _n_spaces) 

Lorsque vous définissez les opérateurs en tant que membres de la classe, le premier argument de l'opérateur est (implicitement) une instance de la classe. Donc, en principe, qui ne pouvait être appelé avec:

MyClass m; 
m << ??? 

Mais voici un problème: une fonction d'opérateur appelé en utilisant la notation infixe ne peut avoir deux paramètres, et dans le cas d'une fonction d'opérateur de membre, le premier argument est implicite. m << x ne peut être mis en œuvre que par MyClass::operator<<(decltype(x)). En résumé, vous ne pouvez implémenter cela qu'avec un non-membre operator<< et le second argument de cette surcharge doit être un type d'utilisateur. Donc, ce qui suit fonctionne très bien:

struct space_t { 
    unsigned x; 
    space_t(unsigned x) : x(x) {} 
    operator unsigned() const { return x; } 
}; 

std::ostream& operator<< (std::ostream& os, space_t n) { 
    for (unsigned i = 0; i < n; ++i) os << " "; 
    return os; 
} 

Voir sur ideeone

+0

Mais si je remplace le typedef par un struct, la fonction surchargée dans une classe fonctionne bien. – Michele

+0

@Michele: Voulez-vous dire ceci: http://ideone.com/1y9Akx (Mais cela donne l'erreur de compilation attendue). – rici

+0

Avec le mot clé ami utilisé avec la surcharge, cela fonctionne – Michele

2

Typedef ne crée pas nouveau type, il crée simplement alias de type existant. Possbile vous pouvez utiliser quelque chose comme ceci:

struct SpaceType { 
    int space_cnt; 
}; 
... 
std::ostream& operator<< (std::ostream& _os, SpaceType _n_spaces) { 
    for (int _C = 0; _C < _n_spaces.space_cnt; _C++) 
     _os << " "; 
    return _os; 
    } 
... 
SpaceType spaces = { 5 }; 
std::cout << _a << spaces << _b << std::endl; 
+0

Je connaissais cette solution mais je voudrais éviter l'utilisation de struct à cette fin – Michele

+0

@Michele: Pourquoi? Il n'y a pas de coût réel. – rici

+0

Parce que je sens que je suis en train de gaspiller des lignes de codes en écrivant une structure et des instances juste pour un tas d'espaces. De toute façon, s'il n'y a pas de solution c'est bon. – Michele

0

Je suis d'accord avec RICI. Parfaitement expliqué.