Переместить конструктор (ссылка на rvalue) в неявном преобразовании - PullRequest
1 голос
/ 15 сентября 2010

Я обновляю проект C ++ с MSVC 2008 до 2010, и из-за нового конструктора перемещения CComBSTR [CComBSTR (CComBSTR &&)]] я получаю ошибку компилятора из-за неоднозначного вызова.

По сути, у нас есть класс String, очень похожий на std :: wstring, у которого есть оператор приведения к CComBSTR.Это похоже на следующий код:

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 config = GetObjectConfig();
CComBSTR objectName( config.GetName() );

В VS2008 это будет работать, потому что объект CStringбудет неявно преобразован в значение CComBSTR, и конструктор копирования CComBSTR (с использованием const CComBSTR &) будет вызван для создания objectName.

В VS2010 с C ++ 0x, однако, компилятор выдает неоднозначную ошибку вызова, потому чтоЗначение CComBSTR, кажется, подходит как конструктору копирования, так и конструктору перемещения.

Хотя это немного неуклюже, мое решение этой проблемы состоит в том, чтобы static_cast вызывать GetName:

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

Обе строки компилируютсябез ошибок, но мне нужен ваш совет о том, является ли это незаконным, плохой практикой или неопределенным.Спасибо.

1 Ответ

1 голос
/ 08 марта 2011

Для меня это похоже на ошибку VC2010.Либо так, либо я неправильно эмулировал вашу ситуацию на моем компьютере (у меня нет VC2010).Вот что я делаю:

#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() );
}

Для меня на g ++ - 4.4 и clang (с -std = c ++ 0x) это компилируется нормально.И он либо вызывает, либо пропускает вызов CComBSTR (CComBSTR &&).Моя рекомендация обойти эту подозрительную ошибку просто:

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

Это эквивалентно вашему:

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

, но не так страшно (и столь же эффективно).Если вы хотите остаться с static_cast, перейдите с приведением к CComBSTR &&, так как это, вероятно, будет более эффективным, чем построение из const lvalue.

...