jeudi 15 novembre 2018

Failure to deduce template argument std::function from lambda function

While exploring templates in C++, I stumbled upon the example in the following code:

#include <iostream>
#include <functional>

template <typename T>
void call(std::function<void(T)> f, T v)
{
    f(v);
}

int main(int argc, char const *argv[])
{
    auto foo = [](int i) {
        std::cout << i << std::endl;
    };
    call(foo, 1);
    return 0;
}

To compile this program, I am using the GNU C++ Compiler g++:

$ g++ --version // g++ (Ubuntu 6.5.0-1ubuntu1~16.04) 6.5.0 20181026

After compiling for C++11, I get the following error:

$ g++ -std=c++11 template_example_1.cpp -Wall

template_example_1.cpp: In function ‘int main(int, const char**)’:
template_example_1.cpp:15:16: error: no matching function for call to ‘call(main(int, const char**)::<lambda(int)>&, int)’
     call(foo, 1);
                ^
template_example_1.cpp:5:6: note: candidate: template<class T> void call(std::function<void(T)>, T)
 void call(std::function<void(T)> f, T v)
      ^~~~
template_example_1.cpp:5:6: note:   template argument deduction/substitution failed:
template_example_1.cpp:15:16: note:   ‘main(int, const char**)::<lambda(int)>’ is not derived from ‘std::function<void(T)>’
     call(foo, 1);
                ^

(same for C++14 and C++17)

From the compiler error and notes I understand that the compiler failed to deduce the type of the lambda, since it cannot be matched against std::function.

Looking at previous questions (1, 2, 3, and 4) regarding this error, I am still confused about it.

As pointed out in answers from questions 3 and 4, this error can be fixed by explicitly specifying the template argument, like so:

int main(int argc, char const *argv[])
{
    ...
    call<int>(foo, 1); // <-- specify template argument type
    // call<double>(foo, 1) // <-- works! Why?
    return 0;
}

However, when I use other types instead of int, like double, float, char, or bool, it works as well, which got me more confused.

So, my questions are as follow:

  • Why does it work when I explicitly specify int (and others) as the template argument?
  • Is there a more general way to solve this?

Aucun commentaire:

Enregistrer un commentaire