简体   繁体   English

如何将 function 模板作为(模板)参数传递给 function 模板?

[英]How can I pass a function template as (template) argument to a function template?

Currently, I have a code like目前,我有一个代码

#include <cstdint>
#include <iostream>

template<std::uint32_t idx>
void f() {
    std::cout << "f(" << idx << ")\n";
}

template<std::uint32_t n>
void loop1() {
    f<n>();
    if constexpr (n > 0) {
        loop1<n - 1>();
    }
}

template<std::uint32_t idx>
void g() {
    std::cout << "g(" << idx << ")\n";
}

template<std::uint32_t n>
void loop2() {
    g<n>();
    if constexpr (n > 0) {
        loop2<n - 1>();
    }
}

int main() {
    loop1<4>();
    loop2<2>();
}

It's necessary for f , g , loop1 and loop2 to be function templates. fgloop1loop2必须是 function 模板。 Now, I have to add more functions, but loop1 and loop2 will always be the same, a recursive template loop.现在,我必须添加更多功能,但loop1loop2将始终相同,一个递归模板循环。

How can I pass the function template as (template) argument to loop to achieve something like:我如何将 function 模板作为(模板)参数传递给loop以实现类似的目的:

#include <cstdint>
#include <iostream>

template<std::uint32_t idx>
void f() {
    std::cout << "f(" << idx << ")\n";
}

template<std::uint32_t idx>
void g() {
    std::cout << "g(" << idx << ")\n";
}

template<std::uint32_t n, typename h>
void loop() {
    h<n>();
    if constexpr (n > 0) {
        loop<n - 1, h>();
    }
}

int main() {
    loop<4, h>();
    loop<2, h>();
}

I prefer to pass the function as template argument at compile time, but a solution to pass the function template as function argument at runtime would also solve my problem, eg我更喜欢在编译时将 function 作为模板参数传递,但是在运行时将 function 模板作为 function 参数传递的解决方案也可以解决我的问题,例如

#include <cstdint>
#include <iostream>

template<std::uint32_t idx>
void f() {
    std::cout << "f(" << idx << ")\n";
}

template<std::uint32_t idx>
void g() {
    std::cout << "g(" << idx << ")\n";
}

template<std::uint32_t n, typename T>
void loop(T h) {
    h<n>();
    if constexpr (n > 0) {
        loop<n - 1>(h);
    }
}

int main() {
    loop<4>(h);
    loop<2>(h);
}

or要么

#include <cstdint>
#include <iostream>

template<std::uint32_t idx>
void f() {
    std::cout << "f(" << idx << ")\n";
}

template<std::uint32_t idx>
void g() {
    std::cout << "g(" << idx << ")\n";
}

template<std::uint32_t n, template<std::uint32_t> typename F>
void loop(F h) {
    h<n>();
    if constexpr (n > 0) {
        loop<n - 1>(h);
    }
}

int main() {
    loop<4>(h);
    loop<2>(h);
}

Is this even possible?这可能吗? I know, that all of my approaches are wrong syntax.我知道,我所有的方法都是错误的语法。 It's just to illustrate, what I want to achieve.这只是为了说明,我想要实现的目标。

You cannot do this with free functions but you can do something similar to what you want to have with class template static member functions:您不能使用自由函数执行此操作,但您可以使用 class 模板 static 成员函数执行类似于您想要的操作:

#include <cstdint>
#include <iostream>

template<std::uint32_t idx>
struct F {
  static void function() {
    std::cout << "f(" << idx << ")\n";
  }
};

template<std::uint32_t idx>
struct G {
  static void function() {
    std::cout << "g(" << idx << ")\n";
  }
};

template<std::uint32_t n, template<std::uint32_t> typename T>
void loop() {
    T<n>::function();
    if constexpr (n > 0) {
        loop<n - 1, T>();
    }
}

int main() {
    loop<4, F>();
    loop<2, G>();
}

Here's a demo .这是一个演示

For this I would recommend a either a generic or a template lambda. The goal of our solution would be to send in a predicate that can receive the parameter idx at compile time.为此,我会推荐一个通用的或模板 lambda。我们的解决方案的目标是发送一个可以在编译时接收参数idx的谓词。

With template lambda (C++20):使用模板 lambda (C++20):

#include <cstdint>
#include <iostream>

template<std::uint32_t idx>
void f() {
    std::cout << "f(" << idx << ")\n";
}

template<std::uint32_t idx>
void g() {
    std::cout << "g(" << idx << ")\n";
}

template<std::uint32_t n, typename F>
void loop(F h) {
    h.template operator()<n>();
    if constexpr (n > 0) {
        loop<n - 1>(h);
    }
}

int main() {
    loop<4>([]<std::uint32_t idx>() {
        return f<idx>();
    });
    loop<2>([]<std::uint32_t idx>() {
        return g<idx>();
    });
}

This is the closest solution to what you posted.这是与您发布的内容最接近的解决方案。 The lambda there is a type with a templated operator() . lambda 有一个带有模板化operator()的类型。


With generic lambda (compatible with C++14)使用通用 lambda(与 C++14 兼容)

#include <cstdint>
#include <iostream>

template<std::uint32_t idx>
void f() {
    std::cout << "f(" << idx << ")\n";
}

template<std::uint32_t idx>
void g() {
    std::cout << "g(" << idx << ")\n";
}

template<std::uint32_t n, typename F>
void loop(F h) {
    h(std::integral_constant<std::uint32_t, n>{});
    if constexpr (n > 0) {
        loop<n - 1>(h);
    }
}

int main() {
    loop<4>([](auto idx) {
        return f<idx>();
    });
    loop<2>([](auto idx) {
        return g<idx>();
    });
}

This solution is using generic lambdas, but is still a templated lambda in reality.此解决方案使用通用 lambda,但实际上仍然是模板化的 lambda。 idx is taking the type of std::integral_constant which can be sent as template parameter since its conversion operator to std::uint32_t is constexpr. idx采用可以作为模板参数发送的std::integral_constant类型,因为它到std::uint32_t的转换运算符是 constexpr。

I would replace the template functions f and g by structs F and G respectively, each one with a template method invoke :我将分别用结构FG替换模板函数fg ,每个函数都有一个模板方法invoke

struct F {
  template<std::uint32_t idx>
  void invoke() {
    std::cout << "f(" << idx << ")\n";
  }
};

struct G {
  template<std::uint32_t idx>
  void invoke() {
    std::cout << "g(" << idx << ")\n";
  }
};

template<std::uint32_t n, typename F>
void loop(F h) {
    h.template invoke<n>();
    if constexpr (n > 0) {
        loop<n - 1>(h);
    }
}

Nothing stops you from adding template functions f and g that call invoke for F and G respectively:没有什么能阻止您添加分别为FG调用invoke的模板函数fg

template<std::uint32_t idx>
void f() {
  F().invoke<idx>();
}

template<std::uint32_t idx>
void g() {
  G().invoke<idx>();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM