4

How to prevent floating-point being implicitly converted to integral value at function call?

#include <iostream>

void fn(int x) {
    std::cout<<"fn("<<x<<")\n";
}

int main() {
    std::cout<<"Hello, this is 301014 :)\n";
    fn(2);
    fn(3.5);
    return 0;
}

Here the outputs are 2 and 3 respectively.
I am compiling with g++ -std=c++11 31014.cpp -o 31014 -v. And there is no mention of 3.5 being converted to 3.
Is there a way to prevent, or atleast detect, this?

Kindly help me out, please.

JaMiT
  • 14,422
  • 4
  • 15
  • 31
Supreeto
  • 198
  • 9
  • 2
    `-Wconversion` or `-Wfloat-conversion` will give you a warning. https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html – Retired Ninja Nov 04 '22 at 06:59

4 Answers4

7

There are multiple ways to handle this in .

Method 1: You SFINAE the function template fn by using std::enable_if.

template<typename T>
typename std::enable_if<std::is_same<T, int>::value>::type fn(T x) {
    std::cout << "fn(" << x << ")\n";
}

int main() {
    std::cout << "Hello, this is 301014 :)\n";
    fn(2);       // works
    // fn(3.5);  // won't work;
}

Demo


Method 2: Alternatively, delete the functions using =delete, which shouldn't take place in template deduction.

void fn(int x) {                          // #1
    std::cout << "fn(" << x << ")\n";
}
template<typename T> void fn(T) = delete; // #2

int main() {
    std::cout << "Hello, this is 301014 :)\n";
    fn(2);      // works  using #1
    // fn(3.5); // won't work since it uses #2
}

Demo

Jason
  • 36,170
  • 5
  • 26
  • 60
5

Another way to solve this is to add template<typename T> void fn(T)=delete; (also works with older c++ standards):

#include <iostream>

template<typename T> void fn(T)=delete;

void fn(int x) {
    std::cout<<"fn("<<x<<")\n";
}

int main() {
    std::cout<<"Hello, this is 301014 :)\n";
    fn(2);
    fn(3.5); // now gives error
    return 0;
}

  • This is the solution I would prefer, because it does not force me to implement the function taking `int` as a template. – j6t Nov 04 '22 at 08:49
4

There are several ways to prevent implicit conversion.

  1. Using std::enable_if and std::is_same.

    template <class T, std::enable_if_t<std::is_same_v<T,int>,bool> = false>
    void func(T x) {
        cout << x << endl;   
    }
    
  2. In C++ 20, one can use requires

    template <class T>
         requires std::same_as(T,int)
    void func(T x) {
       // ....
    }
    
  3. Using concept.

    template <class T>
    concept explicit_int = std::same_as<T,int>;
    
    void func(explicit_int auto x) {
       // ...
    }
    
JeJo
  • 30,635
  • 6
  • 49
  • 88
GAVD
  • 1,977
  • 3
  • 22
  • 40
0

Enable the right compiler warnings.

GCC and Clang call this warning -Wconversion.

With this flag, I get:

<source>:10:8: warning: implicit conversion from 'double' to 'int' changes value from 3.5 to 3 [-Wliteral-conversion]
    fn(3.5);
    ~~ ^~~
HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207