Подтвердить что ты не робот

Можете ли вы использовать явное выражение ключевого слова для предотвращения автоматического преобразования параметров метода?

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

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

4b9b3361

Ответ 1

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

С С++ 11 вы можете объявить шаблонную функцию как delete d. Вот простой пример:

#include <iostream>

struct Thing {
    void Foo(int value) {
        std::cout << "Foo: value" << std::endl;
    }

    template <typename T>
    void Foo(T value) = delete;
};

При попытке вызвать Thing::Foo с параметром size_t выдается следующее сообщение об ошибке:

error: use of deleted function
    ‘void Thing::Foo(T) [with T = long unsigned int]

В коде до С++ 11 это можно сделать с помощью неопределенной закрытой функции.

class ClassThatOnlyTakesBoolsAndUIntsAsArguments
{
public:
  // Assume definitions for these exist elsewhere
  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:
  // You can leave these undefined
  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);
};

Недостатком является то, что в этом случае код и сообщение об ошибке менее понятны, поэтому следует выбирать опцию С++ 11, когда она доступна.

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

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

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

Ответ 2

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

Ответ 3

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

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" будет ясно, какой аргумент есть.

Ответ 4

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

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

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

Ответ 5

В настоящее время принятый ответ answer (с использованием закрытой шаблонной функции) хорош, но устарел. В С++ 11 мы можем использовать функции delete d вместо этого:

#include <iostream>

struct Thing {
    void Foo(int value) {
        std::cout << "Foo: value" << std::endl;
    }

    template <typename T>
    void Foo(T value) = delete;
};

int main() {
    Thing t;
    int int_value = 1;
    size_t size_t_value = 2;

    t.Foo(int_value);

    // t.Foo(size_t_value);  // fails with below error
    // error: use of deleted function
    //   ‘void Thing::Foo(T) [with T = long unsigned int]

    return 0;
}

Это более точно передает цель исходного кода и предоставляет пользователю более четкое сообщение об ошибке при попытке использовать функцию с запрещенными типами параметров.

Ответ 6

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

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

Ответ 7

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

Ответ 8

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