我如何编写一个模板类,而不是几个模板类

How do I write one template class instead of several ones?

本文关键字:几个 一个 何编写      更新时间:2023-10-16

有几个模板类,可与功能指针一起使用一个,两个等。

template <typename A1, int(*func)(A1)>
class Something1
{
public:
    static void f()
    {
        A1 a1;
        // ...
        int r = func(a1);
        // ...
    }
};
template <typename A1, typename A2, int(*func)(A1, A2)>
class Something2
{
public:
    static void f()
    {
        A1 a1;
        A2 a2;
        // ...
        int r = func(a1, a2);
        // ...
    }
};

我如何编写一个可以与指示函数的指针一起使用的模板类?有可能吗?

您无法定义一个只有一个模板参数并接受函数指针的类模板必须推论的参数。
为此,您必须使用类似的东西:

template<typename F, F *func>
struct S;
template<typename R, typename... A, R(*f)(A...)>
struct S<R(A...), f> {};

和一个类似这样的丑陋符号:

S<decltype(f), &f> s;

可能的替代方法是将函数指针用作构造函数的参数:

#include<type_traits>
#include<utility>
template<typename>
struct S;
template<typename R, typename... A>
struct S<R(A...)> {
    S(R(*f)(A...)): f{f} {}
    R operator()(A... args) { return f(args...); }
private:
    R(*f)(A...);
};
void g() {}
int h(int) { return 0; }
int main() {
    S<void(void)> s1{&g};
    S<int(int)> s2{&h};
    s1();
    s2(42);
}

如果您想进一步发展并具有更灵活的解决方案,则可以使用lambdas和一种工厂方法来解决它:

#include<type_traits>
#include<utility>
template<typename F>
struct S: F { S(F &&f): F{std::forward<F>(f)} {} };
template<typename F>
constexpr auto create(F &&f)
-> decltype(S<typename std::decay<F>::type>{std::forward<F>(f)}) {
    return S<typename std::decay<F>::type>{std::forward<F>(f)};
}
void g() {}
int h(int) { return 0; }
int main() {
    auto s1 = create([](){ g(); });
    auto s2 = create([](int i){ return h(i); });
    s1();
    s2(42);
}

作为旁注,如果您可以使用C 14,则最后一段的语法会变得更好:

#include<type_traits>
#include<utility>
template<typename F>
struct S: F { S(F &&f): F{std::forward<F>(f)} {} };
template<typename F>
constexpr auto create(F &&f) {
    return S<std::decay_t<F>>{std::forward<F>(f)};
}
void g() {}
int h(int) { return 0; }
int main() {
    auto s1 = create([](){ g(); });
    auto s2 = create([](auto&&... args){ return h(std::forward<decltype(args)>(args)...); });
    s1();
    s2(42);
}

使用类/结构模板专业化,可以做类似的事情。

而不是您的SomethingN类,而是开发了以下foo struct;我已经实现了一个bar()方法,该方法接收到Args...的列表以传递给func和一个未接收的方法baz(),并为func

创建默认构造的Args...
#include <iostream>
template <typename F, F>
struct foo;
template <typename ... Args, int(*func)(Args...)>
struct foo<int(*)(Args...), func>
 {
   int bar (Args ... args)
    { return func(args...); }
   int baz ()
    { return func(Args{}...); }
 };

int func0 ()
 { return 0; }
int func1 (int)
 { return 1; }
int func2 (std::string const &, long)
 { return 2; }
int func3 (char, std::string const &, long)
 { return 3; }
int main ()
 {
   foo<decltype(&func0), func0>  f0;
   foo<decltype(&func1), func1>  f1;
   foo<decltype(&func2), func2>  f2;
   foo<decltype(&func3), func3>  f3;
   std::cout << f0.bar() << std::endl;                  // print 0
   std::cout << f1.bar(3) << std::endl;                 // print 1
   std::cout << f2.bar("string", 2L) << std::endl;      // print 2
   std::cout << f3.bar('c', "string", 2L) << std::endl; // print 3
   std::cout << f0.baz() << std::endl; // print 0
   std::cout << f1.baz() << std::endl; // print 1
   std::cout << f2.baz() << std::endl; // print 2
   std::cout << f3.baz() << std::endl; // print 3
 }