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
内部)。