Перегрузка оператора C++ и неявное преобразование

Важное отличие, которое следует отметить, в дополнение к другим ответам, заключается в том, что yield в C # нельзя использовать как выражение, только как утверждение.

Пример использования выражения yield в Python (пример вставлен из здесь ):

def echo(value=None):
  print "Execution starts when 'next()' is called for the first time."
  try:
    while True:
       try:
         value = (yield value)
       except GeneratorExit:
         # never catch GeneratorExit
         raise
       except Exception, e:
         value = e
     finally:
       print "Don't forget to clean up when 'close()' is called."

generator = echo(1)
print generator.next()
# Execution starts when 'next()' is called for the first time.
# prints 1

print generator.next()
# prints None

print generator.send(2)
# prints 2

generator.throw(TypeError, "spam")
# throws TypeError('spam',)

generator.close()
# prints "Don't forget to clean up when 'close()' is called."

7
задан SadSido 22 October 2009 в 14:34
поделиться

5 ответов

Предполагая, что вы хотите, чтобы специализированная версия была выбрана для любого целочисленного типа (а не только int в частности, вы могли бы сделать это как функцию шаблона и использовать Boost. EnableIf для удаления этих перегрузок из доступного набора перегрузок, если операнд не является целочисленным типом.

#include <cstdio>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_integral.hpp>

class CFixed
{
public:
   CFixed( int   ) {}
   CFixed( float ) {}
};

CFixed operator* ( const CFixed& a, const CFixed&  )
{ puts("General CFixed * CFixed"); return a; }

template <class T>
typename boost::enable_if<boost::is_integral<T>, CFixed>::type operator* ( const CFixed& a, T  )
{ puts("CFixed * [integer type]"); return a; }

template <class T>
typename boost::enable_if<boost::is_integral<T>, CFixed>::type operator* ( T , const CFixed& b )
{ puts("[integer type] * CFixed"); return b; }


int main()
{
    CFixed(0) * 10.0f;
    5 * CFixed(20.4f);
    3.2f * CFixed(10);
    CFixed(1) * 100u;
}

Естественно, вы также можете использовать другое условие, чтобы сделать эти перегрузки доступными, только если T = int: typename boost :: enable_if , CFixed> :: type ...

Что касается проектирования класса, возможно, вы могли бы больше полагаться на шаблоны. Например, конструктор может быть шаблоном и, опять же,если вам нужно различать целые и действительные типы, должна быть возможность использовать этот метод.

1
ответ дан 7 December 2019 в 05:25
поделиться

Если у вас есть конструкторы, которые можно вызывать только с одним аргументом, вы фактически создали оператор неявного преобразования. В вашем примере везде, где требуется CFixed , можно передать как int , так и float . Это, конечно, опасно, потому что компилятор может молча сгенерировать код, вызывающий неправильную функцию, вместо того, чтобы лаять на вас, когда вы забыли включить объявление какой-либо функции.

Поэтому хорошее практическое правило гласит, что всякий раз, когда вы пишете конструкторы, которые могут быть вызваны только с одним аргументом (обратите внимание, что этот foo (int i, bool b = false) может быть вызван с одним аргументом, даже если он принимает два аргумента), вы должны сделать этот конструктор явным , если вы действительно не хотите, чтобы сработало неявное преобразование. явные конструкторы не используются компилятором для неявных преобразований.

Вам придется изменить свой класс на этот:

class CFixed
{
   explicit CFixed( int   );
   explicit CFixed( float );
};

Я обнаружил, что есть очень мало исключений из этого правила. ( std :: string :: string (const char *) - довольно известный пример.)

Изменить: Извините, я упустил момент о запрете неявных преобразований из int до float .

Я вижу единственный способ предотвратить это - также предоставить операторы для float .

m извините, я упустил момент о запрете неявных преобразований из int в float .

Я вижу единственный способ предотвратить это - также предоставить операторы для float .

m извините, я упустил момент о запрете неявных преобразований из int в float .

Я вижу единственный способ предотвратить это - также предоставить операторы для float .

3
ответ дан 7 December 2019 в 05:25
поделиться

Вы также должны перегрузить типом float . Преобразование из int в указанный пользователем тип ( CFixed ) имеет более низкий приоритет, чем встроенное преобразование с плавающей запятой в float . Таким образом, компилятор всегда будет выбирать функцию с int , если вы не добавите функцию с float .

Подробнее см. В разделе 13.3 стандарта C ++ 03. Почувствуй боль.

Кажется, я тоже потерял его из виду. :-( UncleBens сообщает, что добавление только числа с плавающей запятой не решает проблему, так как версия с double также должна быть добавлена. Но в любом случае добавление нескольких операторов, связанных со встроенными типов утомительно, но не приводит к комбинаторному повышению.

4
ответ дан 7 December 2019 в 05:25
поделиться

Как насчет того, чтобы сделать преобразование явным ?

0
ответ дан 7 December 2019 в 05:25
поделиться

Согласитесь с sbi, вы обязательно должны сделать свои однопараметрические конструкторы явными.

Однако вы можете избежать взрывного роста в функциях operator <>, которые вы пишете с помощью шаблонов:

template <class T>
CFixed operator* ( const CFixed& a, T b ) 
{ ... } 

template <class T>
CFixed operator* ( T a, const CFixed& b ) 
{ ... } 

В зависимости от от того, какой код находится в функциях, он будет компилироваться только с теми типами, из которых вы поддерживаете преобразование.

0
ответ дан 7 December 2019 в 05:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: