Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 允许函数指针类型的模板参数接受任何返回类型的函数_C++_Templates - Fatal编程技术网

C++ 允许函数指针类型的模板参数接受任何返回类型的函数

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

当函数的返回值未实际使用时,是否有方法允许函数指针类型的模板参数接受任何(而不是特定)返回类型的函数?这里有一个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)
}
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)
}