首页 > 解决方案 > 允许函数指针类型的模板参数接受任何返回类型的函数

问题描述

当函数的返回值没有被实际使用时,有没有办法允许函数指针类型的模板参数接受任何(而不是特定的)返回类型的函数?这是一个 MCVE 来说明我的意思:

int returnInt(int) { return 0; }
void returnVoid(int) { }

template <int (*Func)(int)>
struct foo { void bar(int x) { Func(x); } };

int main(int, char *[]) {
    foo<returnInt> a; // ok
    foo<returnVoid> b; // argument of type "void (*)(int)" is incompatible
                       // with template parameter of type "int (*)(int)"C/C++(458)
}

我知道我可以这样做,作为一种解决方法:

template <typename ReturnType, ReturnType (*Func)(int)>
struct foo { void bar(int x) { Func(x); } };

int main(int, char *[]) {
    foo<int, returnInt> a; // ok
    foo<void, returnVoid> b; // ok
}

甚至这个(在我看来更糟,因为我们失去了对函数类型的参数类型的类型检查并且可能落入 SFINAE):

template <typename FuncType, FuncType *Func>
struct foo { void bar(int x) { Func(x); } };

int main(int, char *[]) {
    foo<decltype(returnInt), returnInt> a; // ok
    foo<decltype(returnVoid), returnVoid> b; // ok
}

但我想知道是否有一种方法可以在不添加没有其他目的的额外模板参数的情况下做到这一点。

标签: c++templates

解决方案


您可以将模板参数声明为auto(自 C++17 起)以使其适用于任何函数指针类型。

template <auto Func>
struct foo { void bar(int x) { Func(x); } };

居住

如果你想用 SFINAE 检查类型:

template <auto Func, std::enable_if_t<std::is_function_v<std::remove_pointer_t<decltype(Func)>>> * = nullptr>
struct foo { void bar(int x) { Func(x); } };

居住

或者仍然将模板参数声明为可能返回任何类型的函数指针。

template <auto (*Func)(int)>
struct foo { void bar(int x) { Func(x); } };

居住


推荐阅读