Как избежать неявных преобразований для неструктурирующих функций?

Как избежать неявного приведения к неструктурирующим функциям?
У меня есть функция, которая принимает целое число в качестве параметра,
но эта функция также будет принимать символы, 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;}

* пожалуйста, обязательно укажите на любое неправильное использование терминологии и допущений

25

Решение

Вы не можете напрямую, потому что char автоматически повышается до int,

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

void function(int i)
{
}
void function(char i);
//or, in C++11
void function(char i) = delete;

Вызов функции с char параметр сломает сборку.

Увидеть http://ideone.com/2SRdM

Терминология: неструктурирующие функции? Вы имеете в виду функцию, которая не является конструктором?

16

Другие решения

Определите шаблонную функцию, которая соответствует всем другим типам:

void function(int); // this will be selected for int only

template <class T>
void function(T) = delete; // C++11

Это потому, что не шаблонные функции с прямым соответствием всегда рассматриваются в первую очередь. Затем рассматриваются шаблонные функции с прямым соответствием — поэтому никогда function<int> будет использоваться. Но для всего остального, как чар, function<char> будет использоваться — и это дает ваши ошибки компиляции:

void function(int) {}

template <class T>
void function(T) = delete; // C++11int 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

Это путь C ++ 03:

// because this ugly code will give you compilation error for all other types
class DeleteOverload
{
private:
DeleteOverload(void*);
};template <class T>
void function(T a, DeleteOverload = 0);

void function(int a)
{}
29

Вот общее решение, которое вызывает ошибку во время компиляции, если 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 C ++, в смысле создания желаемой ошибки компиляции, MinGW g ++ 4.7.1 принимает ее и вызывает конструктор ссылок rvalue!

Я думаю, что это должно быть ошибка компилятора, но я могу ошибаться, так что — кто-нибудь?

Во всяком случае, вот код, который может оказывается стандартным решением (или может оказаться, что это с моей стороны Thinko!):

#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
}
1

Для C ++ 14 (и я полагаю, C ++ 11), вы можете отключить конструкторы копирования, также перегружая rvalue-ссылки:

Пример:
Скажем, у вас есть база Binding<C> класс, где C либо база Constraint класс или унаследованный класс. Скажи, что вы храните Binding<C> по значению в векторе, и вы передаете ссылку на привязку, и вы хотите убедиться, что вы не вызываете неявную копию.

Вы можете сделать это, удалив func(Binding<C>&& x) (согласно примеру с PiotrNycz) для конкретных случаев с rvalue.

Snippet:

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

1

Может быть, вы можете использовать структуру, чтобы сделать вторую функцию приватной:

#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
0

Сначала я попробовал подход PiotrNycz (для C ++ 03, который я вынужден использовать для проекта), затем я попытался найти более общий подход и придумал это ForcedType<T> шаблон класса.

template <typename T>
struct ForcedType {
ForcedType(T v): m_v(v) {}
operator T&() { return m_v; }
operator const T&() const { return m_v; }

private:
template <typename T2>
ForcedType(T2);

T m_v;
};

template <typename T>
struct ForcedType<const T&> {
ForcedType(const T& v): m_v(v) {}
operator const T&() const { return m_v; }

private:
template <typename T2>
ForcedType(const T2&);

const T& m_v;
};

template <typename T>
struct ForcedType<T&> {
ForcedType(T& v): m_v(v) {}
operator T&() { return m_v; }
operator const T&() const { return m_v; }

private:
template <typename T2>
ForcedType(T2&);

T& m_v;
};

Если я не ошибаюсь, эти три специализации должны охватывать все распространенные случаи использования. Я не уверен, действительно ли нужна специализация для rvalue-reference (на C ++ 11 и выше) или достаточно одного значения.

Можно использовать это следующим образом, в случае функции с 3 параметрами, чей 3-й параметр не допускает неявные преобразования:

function(ParamType1 param1, ParamType2 param2, ForcedType<ParamType3> param3);
0
По вопросам рекламы [email protected]