6

I am currently trying to use std::bind to create a std::function<void()> from the function template

template<class Iterator>
void printRange(Iterator first, Iterator last) {
    std::copy(first, last, std::ostream_iterator<typename Iterator::value_type>(std::cout, " "));
    std::cout << std::endl;
}

Conceptually, what I want is

int main() {
    std::vector<int> v{1, 2, 3};
    auto f0 = std::bind(printRange, v.begin(), v.end()); // won't compile, of course
    f0();
    return 0;
}

I understand that this does not compile and I have to instantiate the function template before I can actually use it. For example, the following alternatives would work:

auto f1 = std::bind(printRange<std::vector<int>::const_iterator>, v.begin(), v.end());
auto f2 = std::bind(printRange<decltype(v.begin())>, v.begin(), v.end());
auto f3 = [&v]() { printRange(v.begin(), v.end()); };

I already created a convenience function

template<class Iterator>
std::function<void()> makePrintRangeFunction(Iterator first, Iterator last) {
    return std::bind(printRange<Iterator>, first, last);
}

to ease the process:

auto f4 = makePrintRangeFunction(v.begin(), v.end());

I wonder if it is possible to create a more generic std::function<void()> generator, accepting a function template as a first argument and the function template arguments as a variable-length argument list? If not using built-in language features, maybe via a macro?

7
  • 2
    and a lambda is not acceptable? Commented Jan 20, 2016 at 13:17
  • Yeah, fwiw, I have found lambdas to be so much easier to code and read for all things that would have required bind in the past. Commented Jan 20, 2016 at 13:18
  • @TemplateRex: In that case lambdas are ok, but once I need to capute more than just one variable, I thought std::bind would result in an expression that is more readable... Commented Jan 20, 2016 at 13:54
  • possible duplicate of stackoverflow.com/q/15651488/819272 Commented Jan 20, 2016 at 14:21
  • @Marcel, just use a very 'thin' lambda, which immediately calls the actual function. This will be as readable as bind. Let me know if you'd like to see an example. Commented Jan 20, 2016 at 14:29

3 Answers 3

3

As long as you do not need to have template function return type, you can do this:

#include <functional>
#include <iostream>
#include <typeinfo>


template<typename ... T>
std::function<void()> makePrintRangeFunction(void (*f)(T...), T... param) {
    return std::bind(f, param...);
}

template<typename T, typename V>
void print(T type, V val)
{
    std::cout << typeid(type).name() << '\n' << val << '\n';
}

int main()
{
    int i = 5;
    double d = 10.5;
    auto f = makePrintRangeFunction(print, i, d);
    f();
}
Sign up to request clarification or add additional context in comments.

1 Comment

This is exactly what I was looking for! Thank you very much!
2

Maybe the following code will help :)

template <class F, class... Args>
void test(F&& f, Args&&... args) {
 std::function<typename std::result_of<F(Args...)>::type()> task(
   std::bind(std::forward<F>(f), std::forward<Args>(args)...));
   task();
}

1 Comment

oh i didnt understand well , i think the second answer is what you want.
1

If your compiler supports C++14 you could define a generic lambda wrapper as:

template<typename F>
auto fungen(F f) {
  return [=](auto... args) { f(args...); };
}

Use case:

int main() {
  std::vector<int> v {1, 2, 3, 4};
  auto f = fungen(printRange<std::vector<int>::iterator>);
  f(v.begin(), v.end());
}

Live Demo

3 Comments

I don't really where your solution is different from auto f1 = std::bind(printRange<std::vector<int>::const_iterator>, v.begin(), v.end()); or am I missing something?
It seems that OP wants compiler to deduce template arguments from function parameters. Use case: auto f = fungen(printRange, v.begin(), v.end());. Sadly template templates work only with class types and I do not see if it is possible to twist template argument deduction to work in this case.
@Revolver_Ocelot: ...and if I used a class type instead, I would have to make the template parameter explicit again, right?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.