请考虑以下代码示例:
#include <iostream>
#include <functional>
typedef std::function<void()> func1_t;
typedef std::function<void(int)> func2_t;
struct X
{
X (func1_t f)
{ }
X (func2_t f)
{ }
};
int main ( )
{
X x([](){ std::cout << "Hello, world!\n"; });
}
我确信它不应该编译,因为编译器不应该能够选择两个构造函数中的一个。g-4.7.3显示了这个预期的行为:它说重载构造函数的调用是不明确的。但是,g-4.8.2成功编译了它。
此代码在 C 11 中是否正确,或者它是此版本 g 的错误/功能?
这是完全正确的。因为C11 lambda表达式(以及<code>std::function</code>包装器)创建了函数对象。函数对象的巨大优势在于,即使它们是泛型的,它们仍然是一流的对象。与普通函数模板不同,它们可以传递给函数,也可以从函数返回。
可以通过继承和使用声明显式创建运算符重载集。Mathias Gaunard的以下用法演示了“重载lambda表达式”。
template <class F1, class F2>
struct overload_set : F1, F2
{
overload_set(F1 x1, F2 x2) : F1(x1), F2(x2) {}
using F1::operator();
using F2::operator();
};
template <class F1, class F2>
overload_set<F1,F2> overload(F1 x1, F2 x2)
{
return overload_set<F1,F2>(x1,x2);
}
auto f = overload(
[](){return 1;},
[](int x){return x+1;}
);
int x = f();
int y = f(2);
源
编辑:如果在提供的示例中替换,也许会变得更加清晰
F1 -> std::function<void()>
F2 -> std::function<void(int)>
并看到它在gcc4.7中编译
提供模板化解决方案只是为了证明概念可以扩展到通用代码,消除歧义是可能的。
在您的例子中,当使用GCC4.7这样的旧编译器时,您可以通过显式转换来帮助,gcc会解决问题,正如您在这个实时示例中所看到的
以防万一,如果你想知道,如果你换一种方式(尝试将接受int的lambda转换为不接受参数的std::函数,等等),它将不起作用
在C 11中...
我们来看看< code>std::function(接受任意可调用)的构造函数模板的规范:[func.wrap.func.con]/7-10
template<class F> function(F f);
template <class F, class A> function(allocator_arg_t, const A& a, F f);
7要求:F
应为可复制的
<对于参数类型<code>argtype<code>和返回类型<code>R<code>而言,code>f<code>应<code>可调用<code>(20.10.11.2)。A
的复制构造函数和析构函数不应引发异常。
8后置条件:< code >!*这如果以下任何一项成立:
f
是一个< code >空函数指针。 < li>
f
是指向成员的< code>NULL指针。 < li>
F
是function类模板的实例,而< code >!f
9否则,*this
的目标是f
的副本,初始化为std::mobile(f)
。
10抛出:当f
是函数指针或时,不得抛出异常reference_wrapper
现在,构造或尝试构造(用于重载解析)
std::函数
[res.on.必需]/1
违反函数的Requires:段落中指定的前提条件会导致未定义的行为,除非函数的Throws:段落指定在违反前提条件时引发异常。
因此,恕我直言,即使重载解析的结果也是未定义的。因此,g/libstdc的两个版本在这方面都是一致的。
在 C 14 中,这已更改,请参阅 LWG 2132。现在,
需要 std::函数
的转换构造函数模板来 SFINAE 拒绝不兼容的可调用对象(在下一章中将详细介绍 SFINAE):
template<class F> function(F f);
template <class F, class A> function(allocator_arg_t, const A& a, F f);
7要求:
F
应为可复制的
。
8备注:这些构造函数不得参与重载解析,除非参数类型<code>ArgTypes…</code>和返回类型<code>R</code>可调用<code>f</code>(20.9.11.2)。
[...]
“不得参与重载解决”对应于通过SFINAE拒绝。净效果是,如果您有一组重载的函数
foo
,
void foo(std::function<void(double)>);
void foo(std::function<void(char const*)>);
以及调用表达式
foo([](std::string){}) // (C)
然后明确选择< code>foo
的第二个重载:因为< code>std::function
请注意,由于 LWG 2420,上述措辞略有变化:有一个例外,如果返回类型
R
的 std::函数
void foo(std::function<void()>);
void foo(std::function<bool()>);
foo([]() -> bool {}); // ambiguous
重载解析规则不会尝试在不同的用户定义的转换之间进行排名,因此
foo
的两个重载都是可行的(首先),而且两者都不是更好。
请注意,当SFINAE检查失败时,程序没有格式错误,但该函数对于过载解决方案不可行。例如:
#include <type_traits>
#include <iostream>
template<class T>
auto foo(T) -> typename std::enable_if< std::is_integral<T>::value >::type
{ std::cout << "foo 1\n"; }
template<class T>
auto foo(T) -> typename std::enable_if< not std::is_integral<T>::value >::type
{ std::cout << "foo 2\n"; }
int main()
{
foo(42);
foo(42.);
}
同样,通过在转换构造函数上使用 SFINAE,可以使转换变得不可行:
#include <type_traits>
#include <iostream>
struct foo
{
template<class T, class =
typename std::enable_if< std::is_integral<T>::value >::type >
foo(T)
{ std::cout << "foo(T)\n"; }
};
struct bar
{
template<class T, class =
typename std::enable_if< not std::is_integral<T>::value >::type >
bar(T)
{ std::cout << "bar(T)\n"; }
};
struct kitty
{
kitty(foo) {}
kitty(bar) {}
};
int main()
{
kitty cat(42);
kitty tac(42.);
}
在下面的代码中,对< code>foo的第一次调用不明确,因此无法编译。 第二个在lambda前面添加了< code> ,解析为函数指针重载。 符号在这里做什么?
当我尝试构建上述代码时,gcc给出了以下错误消息。 测验cpp:34:80:错误:从类型“void(派生:)()const”转换为类型“vood(派生:())(int)const”的static_ 自动函数6 = std::bind(static_cast( 我想知道是否有任何方法可以通过类(在这里成功绑定来绑定。感谢您的帮助。
> < li> 有什么不同吗? “保存/转移”功能的最佳方式是什么?
主要内容:C++ 是如何做到函数重载的在实际开发中,有时候我们需要实现几个功能类似的函数,只是有些细节不同。例如希望交换两个变量的值,这两个变量有多种类型,可以是 int、float、char、bool 等,我们需要通过参数把变量的地址传入函数内部。在C语言中,程序员往往需要分别设计出三个不同名的函数,其函数原型与下面类似: 但在 C++中,这完全没有必要。C++ 允许多个函数拥有相同的名字,只要它们的参数列表不同就可以,这就是 函数
本文向大家介绍详解JS函数重载,包括了详解JS函数重载的使用技巧和注意事项,需要的朋友参考一下 JS的函数定义可以指定形式参数名称,多多少少我们会以为js至少可以支持参数个数不同的方法重载,然而遗憾的是这仅仅是一个假象,js所有的参数都是以arguments传递过去的,这个参数类似于数组,在函数调用的时候,所有的实参都是保存在了这个数据结构里面,我们定义函数的时候所指定的形式参数其实是为这个数据结
考虑以下示例: