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

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

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

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

4b9b3361

Ответ 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