Перегрузка оператора преобразования c ++ не удалась - PullRequest
2 голосов
/ 14 апреля 2020

У меня есть код для перегрузки оператора преобразования для различных типов:

#include <string>
#include <iostream>

class MyClass {
   int m_int;
   double m_double;
   std::string m_string;

public:
   MyClass() : m_int{1}, m_double(1.2), m_string{"Test"} {};

   // overload the conversion operator for std::string
   operator std::string() {
      return m_string;
   }

   // overload the conversion operator for all other types
   template <typename T>
   operator T() {
      if (std::is_same<T, int>::value)
         return m_int;
      else
         return m_double;
   }
};

int main() {

   MyClass o;

   int i = o;
   double d = o;
   std::string s = o;

   std::cout << i << " " << " " << d << " " << s << std::endl;
}

Это работает правильно. Но когда я пытаюсь сделать do

std::string s;
s = o;

, компиляция завершается с

error: use of overloaded operator '=' is ambiguous (with operand types 'std::string' (aka 'basic_string<char, char_traits<char>, allocator<char> >') and 'MyClass')

Видимо, компилятор создает оператор преобразования, отличный от std :: string (). Если я удаляю раздел шаблона, компилятор вынужден использовать оператор преобразования std :: string (), и он снова работает. Так чего мне не хватает?

Ответы [ 2 ]

3 голосов
/ 14 апреля 2020

В классе std::string можно использовать operator=() для назначения символов (и, как результат, целых чисел) для std::string. Это означает, что следующий код является приемлемым, потому что operator=(char) существует:

std::string s1;

s1 = '1'; // works fine
s1 = 24; // works fine

Но вы не можете скопировать конструкцию строки, используя символы (и, следовательно, целые числа).

std::string s2  = '1'; // compilation fails
std::string s3 = 24;   // compilation fails

Итак, в вашем случае, когда вы используете копирование, нет никакой двусмысленности, потому что std::string не может быть скопировано с использованием double или int. Но для operator= это неоднозначно, потому что вы можете назначать целые числа в строку, а компилятор не знает, какой оператор преобразования использовать. Другими словами, для этого компилятор может использовать как ваши строковые, так и int операторы преобразования.

0 голосов
/ 14 апреля 2020

Понял, что работает (спасибо моему коллеге NB):

#include <string>
#include <iostream>

class MyClass {
   int m_int;
   double m_double;
   std::string m_string;

public:
   MyClass() : m_int{1}, m_double(1.2), m_string{"Test"} {};

   // overload the conversion operator for std::string
   operator std::string() {
      return m_string;
   }

   // overload the conversion operator for all other types
   template <typename T, typename std::enable_if<
           std::is_same<T, int>::value ||
           std::is_same<T, double>::value
           ,T>::type* = nullptr>
   operator T() {
      if (std::is_same<T, int>::value)
         return m_int;
      else
         return m_double;
   }
};

int main() {

   MyClass o;

   int i = o;
   double d = o;
   std::string s;
   s = o;

   std::cout << i << " " << " " << d << " " << s << std::endl;
}

Так что нужно включить шаблон для всех допустимых типов. Но как только (char) находится в списке типов в std :: enable_if <>, ошибка возникает снова. Очевидно, что оператор std :: string = хочет отобразить на char (см. Пункт 4. выше).

Что я сейчас не понимаю, так это то, почему явно указываются операторы преобразования int () и double () явно НЕ работает:

operator int() {
   return m_int;
}

operator double() {
   return m_double;
}

, хотя это должно быть эквивалентно

   template <typename T, typename std::enable_if<
           std::is_same<T, int>::value ||
           std::is_same<T, double>::value
           ,T>::type* = nullptr>
   operator T() {
      if (std::is_same<T, int>::value)
         return m_int;
      else
         return m_double;
   }

Также не ясно, почему это не работает:

template <typename T, typename std::enable_if<
        std::is_same<T, int>::value ||
        std::is_same<T, double>::value ||
        std::is_same<T, std::string>::value
        ,T>::type* = nullptr>
operator T() {
   if (std::is_same<T, std::string>::value)
      return m_string;
   else if (std::is_same<T, int>::value)
      return m_int;
   else
      return m_double;
}

Может быть, кто-то может дать мне некоторое представление.

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