Можете ли вы использовать явное выражение ключевого слова для предотвращения автоматического преобразования параметров метода?
Я знаю, что вы можете использовать ключевое слово С++ "Явным" для конструкторов классов, чтобы предотвратить автоматическое преобразование типа. Можете ли вы использовать эту же команду для предотвращения преобразования параметров для метода класса?
У меня есть два члена класса, один из которых принимает значение bool как param, а другой - unsigned int. Когда я вызывал функцию с int, компилятор преобразовал параметр в bool и вызвал неправильный метод. Я знаю, в конце концов, я заменил bool, но пока не хочу нарушать другие подпрограммы, поскольку эта новая процедура разработана.
Ответы
Ответ 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.