2010-09-15 13 views
1

Je suis en train de mettre à niveau un projet C++ de MSVC 2008 à 2010, et à cause du nouveau constructeur de déplacement CComBSTR [CComBSTR (CComBSTR & &)], j'obtiens une erreur de compilateur à cause d'un appel ambigu.Déplacer le constructeur (référence rvalue) dans la conversion implicite

Essentiellement, nous avons une classe de cordes, très semblable à std :: wstring qui ont un opérateur coulé à CComBSTR. Ceci est similator au code suivant:

class CString { 
    public: 
    // ... 
    operator CComBSTR() { 
     CComBSTR temp; 
     /* Encoding conversion here */ 
     return temp; 
    } 
} 

class CObjectConfig { 
    public: 
    CString GetName() const { return m_name; } 

    private: 
    CString m_name; 
} 

Maintenant, à certains endroits dans le code, nous les éléments suivants:

CObjectConfig config = GetObjectConfig(); 
CComBSTR objectName(config.GetName()); 

Dans VS2008, cela fonctionnerait parce que l'objet CString serait implicitement converti à un CComBSTR rvalue et le constructeur de copie de CComBSTR (prenant un const CComBSTR &) serait appelé pour construire objectName. En revanche, dans VS2010 avec C++ 0x, le compilateur donne une erreur d'appel ambiguë car CComBSTR rvalue semble s'adapter à la fois au constructeur de copie et au constructeur de déplacement.

Alors un peu maladroit, ma solution à ce problème est de static_cast l'appel à GetName:

CComBSTR objectName(static_cast<const CComBSTR&>(config.GetName())); 
// or 
CComBSTR objectName(static_cast<CComBSTR&&>(config.GetName())); 

Les deux lignes compilez sans erreur, mais j'ai besoin de vos conseils si cela est illégal, une mauvaise pratique ou non définie . Je vous remercie.

Répondre

1

Cela ressemble à un bug VC2010 pour moi. Soit cela, ou j'ai mal émulé votre situation sur mon ordinateur (je n'ai pas VC2010). Voici ce que je fais:

#include <iostream> 

class CComBSTR 
{ 
public: 
    CComBSTR() {std::cout << "CComBSTR()\n";} 
    CComBSTR(const CComBSTR&) {std::cout << "CComBSTR(const CComBSTR&)\n";} 
    CComBSTR(CComBSTR&&) {std::cout << "CComBSTR(CComBSTR&&)\n";} 
}; 

class CString { 
    public: 
    // ... 
    operator CComBSTR() { 
     CComBSTR temp; 
     /* Encoding conversion here */ 
     return temp; 
    } 
}; 

class CObjectConfig { 
    public: 
    CString GetName() const { return m_name; } 

    private: 
    CString m_name; 
}; 

CObjectConfig GetObjectConfig() 
{ 
    return CObjectConfig(); 
} 

int main() 
{ 
    CObjectConfig config = GetObjectConfig(); 
    CComBSTR objectName(config.GetName()); 
} 

Pour moi g ++ - 4.4 et clang (avec std = C++ 0x), cette compile bien. Et il appelle ou élide un appel à CComBSTR (CComBSTR & &). Ma recommandation pour contourner ce bug présumé est tout simplement:

CComBSTR objectName(CComBSTR(config.GetName())); 

Ceci est équivalent à votre:

CComBSTR objectName(static_cast<CComBSTR&&>(config.GetName())); 

mais pas aussi effrayante (et tout aussi efficace). Si vous voulez rester avec le static_cast, puis aller avec le cast à CComBSTR & & que ce sera probablement plus efficace que la construction d'un const lvalue.