Emanuele Sacco
Emanuele Sacco

Reputation: 431

C++ Passing templated functions to function

I need to pass a templated function to a function.

Until now I haven't found any great advices on google. This is what I tried:

#include <iostream>
#include <sstream>
using namespace std;

struct event {
  bool signal;
};

template<typename T>
void out_stream(T &stream, event &evt) {
  stream << evt.signal;
}

template <typename F>
void doOperation(F f)
{
  event test;
  test.signal = 0;
  stringstream ss;

  f(ss, test);
}

int main() {

  doOperation(out_stream);

  return 0;
}

And that's the error the compiler gives me:

main.cc:27:3: error: no matching function for call to 'doOperation'
  doOperation(out_stream);
  ^~~~~~~~~~~
main.cc:16:6: note: candidate template ignored: couldn't infer template argument 'F'
void doOperation(F f)
     ^
1 error generated.

Some (I hope) useful information about my g++ compiler setup:

Thank you in advance :)

Upvotes: 0

Views: 53

Answers (1)

rturrado
rturrado

Reputation: 8054

For this particular case, you could help the compiler deduce T by calling doOperation with out_stream<std::stringstream>.

Also, within doOperation, you need to use f instead of F.

[Demo]

#include <iomanip>  // boolalpha
#include <iostream>  // cout
#include <sstream>  // stringstream

struct event {
    bool signal{};
};

template<typename T>
void out_stream(T& stream, const event& evt) {
    stream << std::boolalpha << evt.signal;
}

template <typename F>
void doOperation(F&& f) {
    std::stringstream ss{};
    f(ss, event{true});
    std::cout << ss.str() << "\n";
}

int main() {
    doOperation(out_stream<std::stringstream>);
}

// Outputs:
//
//   true

As suggested in the comments though, other options you have instead of passing an instantiation of a function template are:

  1. Change out_stream to accept a std::ostream&.
  2. Pass a generic lambda that just calls the instantiation of the function template.

[Demo]

#include <iomanip>  // boolalpha
#include <iostream>  // cout
#include <sstream>  // stringstream

struct event {
    bool signal{};
};

void out_stream1(std::ostream& stream, const event& evt) {
    stream << std::boolalpha << evt.signal;
}

template <typename T>
void out_stream2(T& stream, const event& evt) {
    stream << std::boolalpha << evt.signal;
}

template <typename F>
void doOperation(F&& f) {
    std::stringstream ss{};
    f(ss, event{true});
    std::cout << ss.str() << "\n";
}

int main() {
    doOperation(out_stream1);
    doOperation([](auto& stream, const auto& evt) { out_stream2(stream, evt); });
}

// Outputs:
//
//   true
//   true

Notice also there are no templated functions, but function templates. out_stream is a function template and needs to be instantiated with a given type, e.g. out_stream<std::stringstream>, to become a function. In the call doOperation(out_stream);, the compiler is unable to deduce the type to instantiate out_stream with.

Upvotes: 1

Related Questions