Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7510777
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 29, 20262026-05-29T23:19:44+00:00 2026-05-29T23:19:44+00:00

I am confused about how implicit type conversion works with regard to C++ argument

  • 0

I am confused about how implicit type conversion works with regard to C++ argument lists. In particular, I have a bunch of functions called like inRange(x, start, end), which return a bool depending on whether x is between start and end.

[In this description inRange is just syntactic sugar for (x > start && x < end) — which is still nice when x is a long string or an expensive function — but in the real code there are extra args for handling the open/closed nature of the boundaries.]

I was vague about the types above. In particular there are different implementations for integer and floating point comparisons, and this meant that templates were not really appropriate since there is no C++ linguistic grouping that differentiates int/long/unsigned/size_t etc. from float/double, etc. So I tried to use the type system by defining two versions of inRange with wide enough int/float types:

inline bool inRange(long x, long start, long end)
inline bool inRange(double x, double start, double end)

This won’t catch “long long” or similar, but our code only uses at most doubles and longs. So it looked pretty safe: my hope was that inRange(int, long, long) etc. would implicitly upcast the int to a long and everything would be fine. However, in cases where literal doubles are written sloppily for the floating point comparison (which I want to allow), e.g. inRange(mydouble, 10, 20), I also had to add a bunch of explicit casts to get rid of compiler warnings and ensure that the floating point comparison is used:

inline bool inRange(double value, long low, long high) {
  return inRange(value, (double)low, (double)high);
}
inline bool inRange(double value, double low, long high) {
  return inRange(value, low, (double)high, lowbound, highbound);
}
...

Not so nice — I’d hoped that the conversion of long to double would have been automatic/implicit — but ok. But the next discovery really screwed me: my compiler encountered an inRange with three ints (not longs) as arguments, and said:

call of overloaded ‘inRange(int&, int&, int&)’ is ambiguous

followed by a list of all the inRange functions defined so far! So C++ doesn’t have a preference for (int, int, int) arg lists to be resolved by (long, long, long) rather than by (double, double, double)? Really?

Any help to get me out of this hole would be much appreciated… I’d never have thought something so simple with only primitive types involved could turn out to be so hard to resolve. Making the full set of ~1000 three-arg function signatures with all possible numerical type combinations is not the answer I’m hoping for!

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-29T23:19:45+00:00Added an answer on May 29, 2026 at 11:19 pm

    Templates are the basics here, you just need some SFINAE.

    #include <limits>
    #include <utility>
    
    template <typename T>
    struct is_integral {
      static bool const value = std::numeric_limits<T>::is_integer;
    };
    
    template <typename Integral, typename T>
    typename std::enable_if<is_integral<Integral>::value, bool>::type
    inRange(Integral x, T start, T end) {
      return x >= static_cast<Integral>(start) and x <= static_cast<Integral>(end);
    }
    
    template <typename Real, typename T>
    typename std::enable_if<not is_integral<Real>::value, bool>::type
    inRange(Real x, T start, T end) {
      return x >= static_cast<Real>(start) and x <= static_cast<Real>(end);
    }
    

    In theory, we could be even more lenient and just allow start and end to have different types. If we want to.

    EDIT: Changed to switch to the real version as soon as there are one real, with built-in sanity check.

    #include <limits>
    #include <utility>
    #include <iostream>
    
    template <typename T>
    struct is_integral {
      static bool const value = std::numeric_limits<T>::is_integer;
    };
    
    template <typename T>
    struct is_real {
      static bool const value = not is_integral<T>::value;
    };
    
    template <typename T, typename L, typename R>
    struct are_all_integral {
      static bool const value = is_integral<T>::value and
                                is_integral<L>::value and
                                is_integral<R>::value;
    };
    
    template <typename T, typename L, typename R>
    struct is_any_real {
      static bool const value = is_real<T>::value or
                                is_real<L>::value or
                                is_real<R>::value;
    };
    
    
    template <typename T, typename L, typename R>
    typename std::enable_if<are_all_integral<T, L, R>::value, bool>::type
    inRange(T x, L start, R end) {
      typedef typename std::common_type<T, L, R>::type common;
      std::cout << "  inRange(" << x << ", " << start << ", " << end << ") -> Integral\n";
      return static_cast<common>(x) >= static_cast<common>(start) and
             static_cast<common>(x) <= static_cast<common>(end);
    }
    
    template <typename T, typename L, typename R>
    typename std::enable_if<is_any_real<T, L, R>::value, bool>::type
    inRange(T x, L start, R end) {
      typedef typename std::common_type<T, L, R>::type common;
      std::cout << "  inRange(" << x << ", " << start << ", " << end << ") -> Real\n";
      return static_cast<common>(x) >= static_cast<common>(start) and
             static_cast<common>(x) <= static_cast<common>(end);
    }
    
    int main() {
      std::cout << "Pure cases\n";
      inRange(1, 2, 3);
      inRange(1.5, 2.5, 3.5);
    
      std::cout << "Mixed int/unsigned\n";
      inRange(1u, 2, 3);
      inRange(1, 2u, 3);
      inRange(1, 2, 3u);
    
      std::cout << "Mixed float/double\n";
      inRange(1.5f, 2.5, 3.5);
      inRange(1.5, 2.5f, 3.5);
      inRange(1.5, 2.5, 3.5f);
    
      std::cout << "Mixed int/double\n";
      inRange(1.5, 2, 3);
      inRange(1, 2.5, 3);
      inRange(1, 2, 3.5);
    
      std::cout << "Mixed int/double, with more doubles\n";
      inRange(1.5, 2.5, 3);
      inRange(1.5, 2, 3.5);
      inRange(1, 2.5, 3.5);
    }
    

    Run at ideone:

    Pure cases
      inRange(1, 2, 3) -> Integral
      inRange(1.5, 2.5, 3.5) -> Real
    Mixed int/unsigned
      inRange(1, 2, 3) -> Integral
      inRange(1, 2, 3) -> Integral
      inRange(1, 2, 3) -> Integral
    Mixed float/double
      inRange(1.5, 2.5, 3.5) -> Real
      inRange(1.5, 2.5, 3.5) -> Real
      inRange(1.5, 2.5, 3.5) -> Real
    Mixed int/double
      inRange(1.5, 2, 3) -> Real
      inRange(1, 2.5, 3) -> Real
      inRange(1, 2, 3.5) -> Real
    Mixed int/double, with more doubles
      inRange(1.5, 2.5, 3) -> Real
      inRange(1.5, 2, 3.5) -> Real
      inRange(1, 2.5, 3.5) -> Real
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Possible Duplicate: Why is my return type meaningless? Hi, I'm confused about a particular
I've always been confused about how the linker works, and it's a difficult subject
Confused about triggers: I have two types of records, 'L' library and 'N' normal.
Totally confused about the data types required here. I have this Linq statement: var
I'm a bit confused about how facebook.logout(context) works. Because even after calling log out,
I'm confused about facebook and whether or not facebook is an openid provider like
Very confused about this one. This code in views.py works, but only when I'm
Really confused about what's going on here. I have a class defined as follows:
I'm confused about how threads and synchronization works. I am working through a sample
I'm confused about this bit of code from the HTTP package : type HandlerFunc

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.