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_Overloading - Fatal编程技术网

C++ 默认参数为模板类型的函数

C++ 默认参数为模板类型的函数,c++,templates,overloading,C++,Templates,Overloading,我正在尝试使用具有默认参数的函数作为函数指针模板参数: template <void (*F)()> class A {}; void foo1(int a = 0) {} void foo2() {} int main() { //A<foo1> a1; <-- doesn't work A<foo2> a2; } void foo1(int a) {} void foo1() { foo1(0); } error: in

我正在尝试使用具有默认参数的函数作为函数指针模板参数:

template <void (*F)()>
class A {};

void foo1(int a = 0) {}
void foo2() {}

int main() 
{
    //A<foo1> a1;   <-- doesn't work
    A<foo2> a2;
}
void foo1(int a) {}
void foo1() { foo1(0); }
error: invalid conversion from ‘void (*)(int)’ to ‘void (*)()’
更新
我知道签名是不同的,但我想知道是否有一种方法可以方便地执行此操作,而无需修改所有具有默认参数的函数?

默认参数值不属于函数类型。不能将
foo1
用作不带参数的函数,因为它只带一个参数。如果你不提的话,你的论点会被填满,但它仍然存在


涉及分派函数的变通方法听起来是个不错的解决方案。如果您非常需要它,它甚至可以被模板化。

foo1的签名是
void(int)
,而不是
void()
。这就是为什么它不能转换为
void(*)(


您将默认参数与重载混淆。

我非常确定函数指针具有扩展了所有默认参数的函数签名,并且函数指针无法转换为具有不同签名的函数指针。在标准中找到这一点是另一回事,尽管

我认为本标准的相关条款为8.3.5[dcl.fct]第6段:

。。。返回类型、参数类型列表、ref限定符和cv限定符seq,但不是默认参数(8.3.6)或异常规范(15.4),是函数类型的一部分。[注:函数类型在函数指针、函数引用和成员函数指针的赋值和初始化过程中进行检查。-结束注]

请注意,根据8.3.6[dcl.fct.default]第1段,默认参数的形式为
=value

如果在参数声明中指定了初始值设定项子句,则此初始值设定项子句将用作默认参数


它不会编译,因为
foo1
具有签名:

void foo1(int a);
您试图将其粘贴到指针中:

void F()
函数签名不匹配。
foo1
有一个默认参数这一事实不会改变函数的签名(它仍然可以接受
int

更通用的解决方案 我要说的是,忘了模板吧,它们只是把你限制在这里

就我个人而言,解决回调问题的方法是使用函数对象和参数绑定。可以使用库和绑定默认参数(或和
std::bind2nd
)来完成

这些boost库还内置于新的C++11标准中,如和

值得一看,因为它让您可以做一些非常好的事情,比如为函数提供默认参数,或者使用类成员函数作为回调


< >我链接到的站点都有很多示例代码,并且Boost链接有教程。

< P>根据C++标准的第83.6节,

如果在参数声明中指定了表达式,则此表达式将用作默认参数。在缺少尾随参数的调用中,将使用默认参数

由于
A
不是函数的调用,因此忽略默认参数。事实上,它们在除函数调用之外的所有上下文中都会被忽略

typedef void (*FFF)();
FFF x = foo1;
将不会编译,并生成与尝试使用
foo1
作为模板参数时得到的相同消息:

template <void (*F)()>
class A {};

void foo1(int a = 0) {}
void foo2() {}

int main() 
{
    //A<foo1> a1;   <-- doesn't work
    A<foo2> a2;
}
void foo1(int a) {}
void foo1() { foo1(0); }
error: invalid conversion from ‘void (*)(int)’ to ‘void (*)()’
这是有意义的,因为计算默认参数是调用中的一个单独步骤:

8.3.6.9:每次调用函数时都会计算默认参数


默认参数的存在不会改变函数的签名。例如,您不能使用带有默认参数的单参数函数来重写无参数虚拟成员函数。

取消对该行的注释,它就不会以ideone进行编译。@dasblinkenlight您忘了取消对失败的行的注释。@JaredC啊,再次复制粘贴错误!谢谢取消对行的注释,伙计们;)这里的错误很简单:默认参数是在调用时填充的——函数仍然只有一个实例,其签名包含所有参数:您不能将
(*)()
带到
(*)(int)
函数。@JaredC尽管
foo1
的参数有默认值,函数签名仍然是
void(int)
,并且无法转换为
void(*)(
),是否有方法对类进行模板化,以便F可以具有任意参数?如果F()失败,那么我可以依赖调用站点失败。@除了可变函数(类似于
printf
)之外,JaredC我认为没有好的方法来完成您所寻找的。可变模板很好。我应该把问题改为c++11。@JaredC我指的是旧的变量函数,而不是模板(例如
foo(char*,…)
va_start
/
va_arg
/
va_end
内部)。