C++ 允许函数指针类型的模板参数接受任何返回类型的函数
当函数的返回值未实际使用时,是否有方法允许函数指针类型的模板参数接受任何(而不是特定)返回类型的函数?这里有一个MCVE来说明我的意思:C++ 允许函数指针类型的模板参数接受任何返回类型的函数,c++,templates,C++,Templates,当函数的返回值未实际使用时,是否有方法允许函数指针类型的模板参数接受任何(而不是特定)返回类型的函数?这里有一个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<retur
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)
}
intreturnint(int){return0;}
void returnVoid(int){}
模板
结构foo{void bar(intx){Func(x);};
int main(int,char*[]){
fooa;//好的
foo b;//类型为“void(*)(int)”的参数不兼容
//模板参数类型为“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
}
模板
结构foo{void bar(intx){Func(x);};
int main(int,char*[]){
fooa;//好的
foob;//好的
}
或者甚至是这样(在我看来,这更糟糕,因为我们丢失了对函数类型的参数类型的类型检查,可能会落入SFINAE):
模板
结构foo{void bar(intx){Func(x);};
int main(int,char*[]){
fooa;//好的
foob;//好的
}
但是我想知道是否有一种方法可以做到这一点,而无需添加一个没有其他用途的额外模板参数。您可以将模板参数声明为(自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); } };
模板
我知道我可以这样做,作为一种解决办法:
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
}
[……]
但我想知道是否有一种方法可以做到这一点,而无需添加额外的模板参数,因为它没有其他用途
尽管OP的解决方法提到了其他模板参数,但它们被用作主模板的参数,这妨碍了客户端在使用分派API时在模板参数列表中显式指定它们
这里使用额外模板参数的关键是(如中所示)专门化:
模板
结构foo{
空栏(整数x)=删除;
};
模板
结构foo{
空栏(整数x){
Func(x);
}
};
int returnInt(int){return 0;}
void returnVoid(int){}
int main(){
fooa;//OK(GCC和Clang)
foob;//OK(GCC和Clang)
}
部分特化中的附加模板参数对于客户端是不可见的,并且完全可以从与客户端API相关联的非类型模板参数推断出来。
您使用的是哪个C++版本?@ FrutestAn未指定的——如果它可能是某个特定标准(最多和/或包括C++ 20),这将是一个很好的答案。(目前我的目标是c++17,但不要将其视为对答案的限制。)c++17为非类型模板参数提供了auto
。由于客户端API不是函数模板(或者相反,是类模板),因此答案在很多其他情况下都是专门化的,由于部分类模板专门化提供了详细的实现(/演绎)控制,同时不会使客户机(模板参数)API混乱。我添加了一个答案来展示这种方法。我刚刚发布了一个。
template <auto>
struct foo {
void bar(int x) = delete;
};
template <typename T, typename Return, Return (*Func)(T)>
struct foo<Func> {
void bar(int x) {
Func(x);
}
};
int returnInt(int) { return 0; }
void returnVoid(int) { }
int main() {
foo<returnInt> a; // OK (GCC and Clang)
foo<returnVoid> b; // OK (GCC and Clang)
}