python - 作为参数的嵌套模板函数

标签 python c++ templates

在 Python 中,有一种非常简单的方法来装饰函数,这样您就可以在函数之前和/或之后添加额外的功能。在最简单的形式中,它看起来像这样:

from random import SystemRandom
from time import time
import functools

rdev = SystemRandom()

def time_function(func):
    @functools.wraps(func)
    def run(*args, **kwargs):
        start = time()
        ret = func(*args, **kwargs)
        print("Took {:0.5f}s".format(time()-start))
        return ret
    return run

@time_function
def foo():
    x = [rdev.randint(1, 1000) for _ in range(10000)]
    sorted(x)

foo()  # prints "Took 0.04239s"

我想用 C++ 编写具有类似功能的东西。我想将具有任意参数和返回类型的函数传递给函数并让它执行一些操作。这是我想出的:

#ifndef TIMEIT_H
#define TIMEIT_H
#include <string>
#include <functional>
#include <iostream>
#if defined(_WIN32)
#include <Windows.h>
namespace timeit {
    unsigned long gettime(void) {
        return GetTickCount();
    }
}
#elif defined(__linux__)
namespace timeit{
    unsigned long gettime(void) {
        return 0; // implement later
    }
}
#endif

namespace timeit {
    template <typename> struct timer_s;

    template<typename... Args> // this is required for any void function
    struct timer_s<void(Args ...)> {
        std::function<void(Args ...)> func;
        timer_s(std::function<void(Args ...)> f) : func{ f } {}
        void operator()(unsigned long &time, Args ... args) {
            unsigned long start = gettime();
            func(args ...);
            time = gettime() - start;
            return;
        }
    };

    template <typename T, typename... Args> // this is for any other return type
    struct timer_s<T(Args ...)> {
        std::function<T(Args ...)> func;
        timer_s(std::function<T(Args ...)> f) : func{ f } { }
        T operator()(unsigned long &time, Args ... args) {
            unsigned long start = gettime();
            T ret = func(args ...);
            time = gettime() - start;
            return ret;
        }
    };

    template<typename T, typename... Args>
    timer_s<T(Args...)> timer(T(*func)(Args ...)) {
        return timer_s<T(Args ...)>(std::function<T(Args ...)>(func));
    }
}
#endif//TIMEIT_H

这工作得很好。例如,我几乎可以使用以下函数为任何函数计时:

static std::random_device rdev;

unsigned int foo(size_t size){
    std::vector<unsigned int> nums(size);
    std::mt19937 rand(rdev());
    std::generate(nums.begin(), nums.end(), rand);
    std::sort(nums.begin(), nums.end());
    return nums.back(); // return largest number
}

int main(){
    //foo(0xffff); // normal call
    unsigned long foo_time = 0;
    auto t_foo = timeit::timer(foo);
    unsigned int largest = t_foo(foo_time, 0xffff); // stores time
    std::cout << "Took " << foo_time << "ms\nLargest number: " << largest << "\n";
    return 0;
}

当我尝试直接对诸如 std::sort 之类的模板函数计时时,问题就出现了。如果我指定确切的类型,我只能这样做。我想我想知道 C++ 是否能够进行嵌套模板推导。我希望它推断出我正在使用哪种形式的 std::sort 并动态更改 t_sort 的实现:

我现在在做什么:

static std::random_device rdev;

int main(){
    std::vector<unsigned int> nums(size);
    std::mt19937 rand(rdev());
    std::generate(nums.begin(), nums.end(), rand);
    auto t_sort = timeit::timer(std::sort<std::vector<unsigned int>::iterator>);
    unsigned long sort_time = 0;
    t_sort(sort_time, nums.begin(), nums.end());
}

我想要什么:

static std::random_device rdev;

int main(){
    std::vector<unsigned int> nums(size);
    std::mt19937 rand(rdev());
    std::generate(nums.begin(), nums.end(), rand);
    auto t_sort = timeit::timer(std::sort); // this line is different
    unsigned long sort_time = 0;
    t_sort(sort_time, nums.begin(), nums.end());
}

这可能吗?我最初的 react 可能不是,但如果不是,为什么?

最佳答案

std::sort 不是函数而是函数模板,

一个解决方案是用任何 accept Functor 代替:

namespace timeit {

    template <typename Functor>
    struct timer_s {
        Functor func;
        double time = 0;
        timer_s(Functor  f) : func{ f } {}

        template <typename ... Ts>
        auto operator()(Ts ... args) {
            struct Finally {
                ~Finally() {
                    time = std::chrono::duration_cast<std::chrono::milliseconds>
                              (std::chrono::system_clock::now() - start).count();
                }
                double& time;
                std::chrono::time_point<std::chrono::system_clock> start;
            } finally{time, std::chrono::system_clock::now()};
            return func(std::forward<Ts>(args)...);
        }
    };

    template<typename F>
    timer_s<F> timer(F f) {
        return timer_s<F>(f);
    }
}

然后调用它:

// Generic lambda to wrap std::sort and call the correct one.
auto t_sort = timeit::timer([](auto b, auto e){ return std::sort(b, e); });

std::vector<int> v {4, 8, 23, 42, 15, 16};

t_sort(v.begin(), v.end());

Demo

关于python - 作为参数的嵌套模板函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36707785/

相关文章:

c++ - 在模板化类与非模板化类中的 lambda 属性中捕获它

c++ - C++ 中基于类型的模板函数

python django 如何在模板中按当前用户过滤 object_set.all

c++ - ENOENT 是否意味着分区上的文件太多?

python - 如何在 Python 中循环直到 EOF?

c++ - 如何使用迭代器有条件地从列表中删除元素?

c++ - 函数参数的生命周期是多少(需要引用)?

templates - 模板中标记为 boost::bimap - 它们有效吗?

android - 请参见测试启动状态错误

python - 按模式读取文件