Question

I am providing a library that supports a function bar(). What it does when you pass in a scalar value (like a double, int, whatever) is different from what happens if you pass in something that is not a scalar value (in all expected cases, a user-defined type). So I wrote code like this:

#include <iostream>

class Foo
{
public:
   template <class T> void bar(T const &rhs) { std::cout << "T" << std::endl; }
   void bar(double rhs) { std::cout << "double" << std::endl; }
};

int main()
{
   Foo foo;
   foo.bar(4);
}

The problem with this is on the second line of main(). The result of this code is output of "T". The compiler prefers the template over the call to bar(double), and I am assuming this is because the parameter is an int, which it would rather cast to int const& (since a const& can reference an r-value).

My question is "is there a way I can support every scalar value without explicitly calling them out?" I really don't want to call out every possible type, because... well... there's a lot of them. I would have to cover everything from char to long long, include every combination of volatile and unsigned, and so forth.

I know that just changing the 4 to a 4.0 works, but this is for the public interface to a library, and requiring the user to type 4.0 instead of 4 is just dirty.

Was it helpful?

Solution

Yes, with traits:

#include <type_traits>
#include <iostream>

class Foo
{
public:
   template <class T>
   typename std::enable_if<!std::is_scalar<T>::value, void>::type bar(T const & rhs)
   {
      std::cout << "T" << std::endl;
   }

   void bar(double rhs)
   {
      std::cout << "double" << std::endl;
   }
};

There are six basic categories of types: scalars, functions, arrays, classes, unions and references. And void. Each of them have a corresponding trait. See here for more details.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top