Как избежать неявных преобразований для неконструктивных функций?
Как избежать неявного литья на неконструктивные функции?
У меня есть функция, которая принимает целое число как параметр,
но эта функция также будет принимать символы, bools и longs.
Я верю, что это делает это, неявно бросая их.
Как я могу избежать этого, так что функция принимает только параметры соответствующего типа и откажется от компиляции в противном случае?
Существует ключевое слово "Явный", но оно не работает с неконструктивными функциями.:\
что мне делать?
Следующая программа компилируется, хотя мне бы хотелось:
#include <cstdlib>
//the function signature requires an int
void function(int i);
int main(){
int i{5};
function(i); //<- this is acceptable
char c{'a'};
function(c); //<- I would NOT like this to compile
return EXIT_SUCCESS;
}
void function(int i){return;}
*, пожалуйста, не забудьте указать на неправильное использование терминологии и допущений
Ответы
Ответ 1
Вы не можете напрямую, потому что char
автоматически получает повышение до int
.
Вы можете прибегнуть к трюк: создайте функцию, которая принимает параметр char
as и не реализует ее. Он будет компилироваться, но вы получите ошибку компоновщика:
void function(int i)
{
}
void function(char i);
//or, in C++11
void function(char i) = delete;
Вызов функции с параметром char
приведет к поломке сборки.
См. http://ideone.com/2SRdM
Терминология: неструктурированные функции? Вы имеете в виду функцию, которая не является конструктором?
Ответ 2
Определите функцию шаблона, которая соответствует всем другим типам:
void function(int); // this will be selected for int only
template <class T>
void function(T) = delete; // C++11
Это потому, что функции без шаблонов с прямым сопоставлением всегда считаются первыми. Затем учитываются функция шаблона с прямым соответствием - поэтому никогда не будет использоваться function<int>
. Но для чего-нибудь еще, как char, function<char>
будет использоваться - и это дает ваши ошибки компиляции:
void function(int) {}
template <class T>
void function(T) = delete; // C++11
int main() {
function(1);
function(char(1)); // line 12
}
ОШИБКИ:
prog.cpp: In function 'int main()':
prog.cpp:4:6: error: deleted function 'void function(T) [with T = char]'
prog.cpp:12:20: error: used here
Это путь С++ 03:
// because this ugly code will give you compilation error for all other types
template <class TEST> class A;
template <> class A<int> {};
template <class T>
void function(T)
{
return A<T>();
}
Ответ 3
Здесь общее решение, которое вызывает ошибку во время компиляции, если function
вызывается с чем угодно, кроме int
template <typename T>
struct is_int { static const bool value = false; };
template <>
struct is_int<int> { static const bool value = true; };
template <typename T>
void function(T i) {
static_assert(is_int<T>::value, "argument is not int");
return;
}
int main() {
int i = 5;
char c = 'a';
function(i);
//function(c);
return 0;
}
Он работает, разрешая использовать любой тип для аргумента, но используя is_int
как предикат уровня. Общая реализация is_int
имеет ложное значение, но явная специализация для типа int имеет значение true, так что static assert гарантирует, что аргумент имеет точно тип int
, иначе возникает ошибка компиляции.
Ответ 4
Хорошо, я собирался ответить на этот вопрос с помощью кода ниже, но даже если он работает с Visual С++, в смысле создания желаемой ошибки компиляции MinGW g++ 4.7.1 принимает его и вызывает конструктор ссылок rvalue!
Я думаю, что это ошибка компилятора, но я могу ошибаться, поэтому – кто-нибудь?
В любом случае, здесь код, который может оказаться стандартным решением (или, может оказаться, что это мысля с моей стороны!):
#include <iostream>
#include <utility> // std::is_same, std::enable_if
using namespace std;
template< class Type >
struct Boxed
{
Type value;
template< class Arg >
Boxed(
Arg const& v,
typename enable_if< is_same< Type, Arg >::value, Arg >::type* = 0
)
: value( v )
{
wcout << "Generic!" << endl;
}
Boxed( Type&& v ): value( move( v ) )
{
wcout << "Rvalue!" << endl;
}
};
void function( Boxed< int > v ) {}
int main()
{
int i = 5;
function( i ); //<- this is acceptable
char c = 'a';
function( c ); //<- I would NOT like this to compile
}
Ответ 5
Для С++ 14 (и я считаю, что С++ 11) вы можете отключить конструкторы копирования, перегружая также rvalue-ссылки:
Пример:
Скажем, у вас есть базовый класс Binding<C>
, где C
- либо базовый класс Constraint
, либо унаследованный класс. Предположим, что вы сохраняете Binding<C>
по значению в векторе и передаете ссылку на привязку, и вы хотите, чтобы вы не вызывали неявную копию.
Вы можете сделать это, удалив func(Binding<C>&& x)
(по одному примеру PiotrNycz) для конкретных случаев с ссылкой на ссылочный номер.
Отрывок:
template<typename T>
void overload_info(const T& x) {
cout << "overload: " << "const " << name_trait<T>::name() << "&" << endl;
}
template<typename T>
void overload_info(T&& x) {
cout << "overload: " << name_trait<T>::name() << "&&" << endl;
}
template<typename T>
void disable_implicit_copy(T&& x) = delete;
template<typename T>
void disable_implicit_copy(const T& x) {
cout << "[valid] ";
overload_info<T>(x);
}
...
int main() {
Constraint c;
LinearConstraint lc(1);
Binding<Constraint> bc(&c, {});
Binding<LinearConstraint> blc(&lc, {});
CALL(overload_info<Binding<Constraint>>(bc));
CALL(overload_info<Binding<LinearConstraint>>(blc));
CALL(overload_info<Binding<Constraint>>(blc));
CALL(disable_implicit_copy<Binding<Constraint>>(bc));
// // Causes desired error
// CALL(disable_implicit_copy<Binding<Constraint>>(blc));
}
Вывод:
>>> overload_info(bc)
overload: T&&
>>> overload_info<Binding<Constraint>>(bc)
overload: const Binding<Constraint>&
>>> overload_info<Binding<LinearConstraint>>(blc)
overload: const Binding<LinearConstraint>&
>>> overload_info<Binding<Constraint>>(blc)
implicit copy: Binding<LinearConstraint> -> Binding<Constraint>
overload: Binding<Constraint>&&
>>> disable_implicit_copy<Binding<Constraint>>(bc)
[valid] overload: const Binding<Constraint>&
Ошибка (с clang-3.9
в bazel
, когда строка нарушения раскоментирована):
cpp_quick/prevent_implicit_conversion.cc:116:8: error: call to deleted function 'disable_implicit_copy'
CALL(disable_implicit_copy<Binding<Constraint>>(blc));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Полный исходный код: prevent_implicit_conversion.cc
Ответ 6
Возможно, вы можете использовать структуру, чтобы сделать вторую функцию частной:
#include <cstdlib>
struct NoCast {
static void function(int i);
private:
static void function(char c);
};
int main(){
int i(5);
NoCast::function(i); //<- this is acceptable
char c('a');
NoCast::function(c); //<- Error
return EXIT_SUCCESS;
}
void NoCast::function(int i){return;}
Это не скомпилируется:
prog.cpp: In function ‘int main()’:
prog.cpp:7: error: ‘static void NoCast::function(char)’ is private
prog.cpp:16: error: within this context