Search code examples
c++c++11auto

type-deduction using auto for functors


I am relatively new to the C++11 features. I have question regarding the auto feature and how it type-deduces functors. Consider the following code snippet:

bool test1(double a, double b) {
   return (a<b);
}

   bool test2(double a, double b) {
       return (a>b);
   }

   struct Test1 {
       bool operator()(double a, double b) {
          return (a<b);
       }
   };

   struct Test2 {
       bool operator()(double a, double b){
          return (a>b);
       }
   };

   int main() {
       const bool ascending = false; 
      auto comparator =  ascending? test1:test2; // works fine
      auto comparator2 = ascending? Test1():Test2(); // compiler error: imcompatible types
      std::function<bool(double, double)> comparator3 = ascending? Test1():Test2(); // compiler error: imcompatible types;

   }

While auto (and std::function) works fine for the functions, it fails (type-deduction) for the function objects. Why is this? I am missing something fundamental w.r.t type-deduction here.

(I am using Visual Studio 2012)


Solution

  • Per Paragraph 5.16/3 of the C++11 Standard on the conditional (?) operator:

    [...] if the second and third operand have different types and either has (possibly cv-qualified) class type, or if both are glvalues of the same value category and the same type except for cv-qualification, an attempt is made to convert each of those operands to the type of the other. [...] If both can be converted, or one can be converted but the conversion is ambiguous, the program is ill-formed. [...]

    In your case, neither Test1 nor Test2 can be converted to the other type. This is why the compiler is complaining about "incompatible types".

    Nptice, that if this wasn't the case, the type of comparator2 and comparator3 would be determined at run-time based on the value of ascending. However, C++ is a statically-typed language, meaning that the type of all objects has to be determined at compile-time.

    If you need to perform a run-time selection of a comparator and hold the result in one variable, consider first assigning both objects to a functor of the same type that can encapsulate them both, and then performing the selection:

        std::function<bool(double, double)> c1 = Test1();
        std::function<bool(double, double)> c2 = Test2();
        auto c = (ascending) ? c1 : c2;