Можете ли вы использовать ключевое слово явное, чтобы предотвратить автоматическое преобразование параметров метода? - PullRequest
50 голосов
/ 06 октября 2008

Я знаю, что вы можете использовать ключевое слово C ++ «явный» для конструкторов классов, чтобы предотвратить автоматическое преобразование типа. Можете ли вы использовать эту же команду для предотвращения преобразования параметров для метода класса?

У меня есть два ученика, один из которых принимает в качестве параметра bool, а другой - без знака int. Когда я вызвал функцию с int, компилятор преобразовал параметр в bool и вызвал неправильный метод. Я знаю, что в конце концов я заменю bool, но пока не хочу нарушать другие подпрограммы, так как эта новая подпрограмма разработана.

Ответы [ 7 ]

62 голосов
/ 06 октября 2008

Нет, вы не можете использовать явное, но вы можете сделать это вместо:

class ClassThatOnlyTakesBoolsAndUIntsAsArguments
{
public:
  void Method(bool arg1);
  void Method(unsigned int arg1);

  // Below just an example showing how to do the same thing with more arguments
  void MethodWithMoreParms(bool arg1, SomeType& arg2);
  void MethodWithMoreParms(unsigned int arg1, SomeType& arg2);

private:
  template<typename T>
  void Method(T arg1);

  // Below just an example showing how to do the same thing with more arguments
  template<typename T>
  void MethodWithMoreParms(T arg1, SomeType& arg2);
};

Повторите этот шаблон для каждого метода, который принимает bool или unsigned int. Не предоставляйте реализацию для шаблонной версии метода.

Это заставит пользователя всегда явно вызывать версию bool или unsigned int.

Любая попытка вызвать Method с типом, отличным от bool или unsigned int, не удастся скомпилировать, поскольку член является частным, конечно, с учетом стандартных исключений из правил видимости (друг, внутренние вызовы и т. Д.) .). Если что-то, имеющее доступ, вызывает закрытый метод, вы получите ошибку компоновщика.

14 голосов
/ 06 октября 2008

Нет. explicit предотвращает автоматическое преобразование между конкретными классами, независимо от контекста. И, конечно, вы не можете сделать это для встроенных классов.

7 голосов
/ 07 октября 2008

Ниже приведена базовая оболочка, которая может использоваться для создания сильного определения типа:

template <typename V, class D> 
class StrongType
{
public:
  inline explicit StrongType(V const &v)
  : m_v(v)
  {}

  inline operator V () const
  {
    return m_v;
  }

private:
  V m_v; // use V as "inner" type
};

class Tag1;
typedef StrongType<int, Tag1> Tag1Type;


void b1 (Tag1Type);

void b2 (int i)
{
  b1 (Tag1Type (i));
  b1 (i);                // Error
}

Одной из приятных особенностей этого подхода является то, что вы также можете различать разные параметры одного типа. Например, у вас может быть следующее:

class WidthTag;
typedef StrongType<int, WidthTag> Width;  
class HeightTag;
typedef StrongType<int, HeightTag> Height;  

void foo (Width width, Height height);

Клиентам 'foo' будет понятно, какой аргумент есть какой.

2 голосов
/ 07 октября 2008

Что-то, что может работать для вас, это использовать шаблоны. Ниже показано, как шаблонная функция foo<>() специализируется на bool, unsigned int и int. Функция main() показывает, как разрешаются вызовы. Обратите внимание, что вызовы, использующие константу int, в которой не указан суффикс типа, преобразуются в foo<int>(), поэтому вы получите сообщение об ошибке foo( 1), если не будете специализироваться на int. В этом случае вызывающие абоненты, использующие литеральную целочисленную константу, должны будут использовать суффикс "U", чтобы получить вызов для разрешения (это может быть желаемое поведение).

В противном случае вам придется специализироваться на int и использовать суффикс "U" или привести его к unsigned int перед передачей его в версию unsigned int (или, возможно, сделать утверждение, что значение не является '' отрицательно, если вы этого хотите).

#include <stdio.h>

template <typename T>
void foo( T);

template <>
void foo<bool>( bool x)
{
    printf( "foo( bool)\n");
}


template <>
void foo<unsigned int>( unsigned int x)
{
    printf( "foo( unsigned int)\n");
}


template <>
void foo<int>( int x)
{
    printf( "foo( int)\n");
}



int main () 
{
    foo( true);
    foo( false);
    foo( static_cast<unsigned int>( 0));
    foo( 0U);
    foo( 1U);
    foo( 2U);
    foo( 0);
    foo( 1);
    foo( 2);
}
0 голосов
/ 06 октября 2008

bool - это int, которое ограничено либо 0, либо 1. Это и есть концепция возврата 0; логически это то же самое, что сказать return false; (не используйте это в коде).

0 голосов
/ 06 октября 2008

Вы также можете написать версию int, которая вызывает bool.

0 голосов
/ 06 октября 2008

Компилятор дал предупреждение «неоднозначный вызов», которого будет достаточно.

Я занимался разработкой TDD и не понял, что забыл реализовать соответствующий вызов в фиктивном объекте.

...