fetag
fetag

Reputation: 174

lambda type deduction failure

Would anybody like to explain why this code is incorrect for template functions but works well for ordinary function. For instance, if we replace std::copy with non-template functions, no problem.

How to change the code and make it valid for both template and non-template functions?

auto functionSpan = [](auto&& func, auto&&... args) {
    auto t1 = std::chrono::high_resolution_clock::now();
    std::forward<decltype(func)>(func)(std::forward<decltype(args)>(args)...);
    auto t2 = std::chrono::high_resolution_clock::now();
    return std::chrono::duration_cast<std::chrono::microseconds>(t2-t1).count();
};

vector<int> vec {1,2,3,4,5,6,7,8,9};
functionSpan(std::copy, vec.begin(), vec.end(), std::ostream_iterator<int>(std::cout, " "));

Upvotes: 1

Views: 61

Answers (2)

Stephen Newell
Stephen Newell

Reputation: 7828

The problem is that std::copy (and really, any template function) isn't a regular function, so the compiler can't derive it. What the compiler needs is a real function, although you could stamp out the the arguments to std::copy.

The issue with explicitly stamping out the arguments is your code isn't generic anymore, plus it's tedious and error-prone when dealing with iterators. Instead, I'd suggest changing your function signatures a bit:

auto functionSpan = [](auto&& fn) {
    auto t1 = std::chrono::high_resolution_clock::now();
    fn();
    auto t2 = std::chrono::high_resolution_clock::now();
    return std::chrono::duration_cast<std::chrono::microseconds>(t2-t1).count();
};

auto copy_helper = [](auto && ... args) {
    return [args...]() {
        std::copy(args...);
    };
};

std::vector<int> vec {1,2,3,4,5,6,7,8,9};
functionSpan(copy_helper(vec.begin(), vec.end(),
                         std::ostream_iterator<int>(std::cout, " ")
                        ));

This compiles for me (I removed the forwarding to make my life simpler) and runs as expected. You'll have to write a specific helper for each template function, but it's less boilerplate than trying to stamp out the template arguments since you still get most of the type deduction.

Upvotes: 0

Petter
Petter

Reputation: 38624

std::copy does not refer to a single function. You need to specify std::copy<Type>

Upvotes: 1

Related Questions