C ++ 0x идеальная пересылка мешает копировать ctor? - PullRequest
3 голосов
/ 06 июня 2011

Использование MSVC2010 ...

У меня есть структура, которая оборачивает std :: string, со стандартным определенным ctor-движением, а также идеальный ctor для перенаправления аргумента в cd std :: string.

struct Wrapper
{
  std::string value;

  Wrapper()
  {
  }

  Wrapper( Wrapper const& rhs )
    :value(rhs.value)
  {
  }

  Wrapper( Wrapper&& rhs )
    :value(std::move(rhs.value))
  {
  }

  Wrapper& operator=( Wrapper const& rhs )
  {
    value = rhs.value;
    return *this;
  }

  Wrapper& operator=( Wrapper&& rhs )
  {
    value = std::move(rhs.value);
    return *this;
  }


  template<typename StringT>
  Wrapper( StringT&& value )
    :value(std::forward<StringT>(value))
  {
  }
};

Однако теперь кажется, что я не могу скопировать-построить Обертку из другой оболочки

Wrapper w0;
Wrapper w1(w0);

Это приводит к ошибке компиляции, указывающей на идеальный ctor для пересылки, говоря, что он не может конвертировать Wrapper в std :: string. Это правильное поведение? Разве компилятор не должен вызывать копию ctor по сравнению с шаблонной перегрузкой?

1>t:\depot\warp\code\apps\pf_test\main.cpp(56): error C2664: 'std::basic_string<_Elem,_Traits,_Ax>::basic_string(const std::basic_string<_Elem,_Traits,_Ax> &)' : cannot convert parameter 1 from 'Wrapper' to 'const std::basic_string<_Elem,_Traits,_Ax> &'
1>          with
1>          [
1>              _Elem=char,
1>              _Traits=std::char_traits<char>,
1>              _Ax=std::allocator<char>
1>          ]
1>          Reason: cannot convert from 'Wrapper' to 'const std::basic_string<_Elem,_Traits,_Ax>'
1>          with
1>          [
1>              _Elem=char,
1>              _Traits=std::char_traits<char>,
1>              _Ax=std::allocator<char>
1>          ]
1>          No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>          t:\depot\warp\code\apps\pf_test\main.cpp(63) : see reference to function template instantiation 'Wrapper::Wrapper<Wrapper&>(StringT)' being compiled
1>          with
1>          [
1>              StringT=Wrapper &
1>          ]
1>

Если я определю другой экземпляр ctor, который принимает неконстантную ссылку на Wrapper (как показано ниже), тогда все выглядит хорошо ... Это путь вперед? Или я что-то испортил? Или это ошибка в VS2010?

  Wrapper( Wrapper& rhs )
    :value(rhs.value)
  {
  }

1 Ответ

4 голосов
/ 06 июня 2011

Да, это правильное поведение.

В этом случае могут быть вызваны два конструктора - ваш конструктор копирования и шаблонный. Тем не менее, конструктор шаблона может вывести тип на точное совпадение (Wrapper(StringT&&) с StringT = Wrapper& дает идеальное совпадение Wrapper(Wrapper&)) и, таким образом, используется вместо конструктора копирования.

Предложенный обходной путь - используйте std::enable_if из <type_traits>:

template <typename StringT>
Wrapper(StringT&& value,
  typename std::enable_if<
    !std::is_same<
      StringT,
      Wrapper&
    >::value
  >::type* = 0)
  : value(std::forward<StringT>(value))
{ }

Посмотрите, как это работает здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...