C++ 使用std::函数进行重载解析
考虑以下代码示例:C++ 使用std::函数进行重载解析,c++,c++11,lambda,overloading,C++,C++11,Lambda,Overloading,考虑以下代码示例: #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([](){
#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"; });
}
#包括
#包括
typedef std::函数func1_t;
typedef std::函数func2_t;
结构X
{
X(函数1\u t f)
{ }
X(函数2\u t f)
{ }
};
int main()
{
X([]){std::cout它是完全有效的。因为c++11 lambda表达式(以及您的std::function
包装器)创建函数对象。函数对象的强大之处在于,即使它们是泛型的,它们仍然是一流的对象。与普通函数模板不同,它们可以传递给函数,也可以从函数返回
您可以通过继承和使用声明显式创建运算符重载集
模板
结构重载集:F1,F2
{
重载集(F1-x1,F2-x2):F1(x1),F2(x2){
使用F1::operator();
使用F2::运算符();
};
模板
过载设置过载(F1-x1,F2-x2)
{
返回过载设置(x1,x2);
}
自动f=过载(
[](){return 1;},
[](int x){返回x+1;}
);
int x=f();
int y=f(2);
编辑:如果在提供的示例中替换
F1 -> std::function<void()>
F2 -> std::function<void(int)>
F1->std::function
F2->标准::函数
及
模板化的解决方案只是为了证明概念可以扩展到通用代码,并且可以消除歧义
在您的情况下,当使用gcc 4.7等较旧的编译器时,您可以通过显式强制转换和
以防万一,在C++11中,如果换成另一种方式(尝试将接受int的lambda转换为不接受参数的std::函数等等),它将不起作用。
让我们看一下std::function
(它接受任何可调用的)的构造函数模板的规范:[func.wrap.func.con]/7-10
7要求:F
应可复制
8备注:这些施工人员不得参与超载
解析,除非参数类型的f
是可调用的(20.9.11.2)
ArgTypes…
和返回类型R
[……]
“不得参与过载解决”对应于SFINAE的拒绝。净效果是,如果您有一组过载功能foo
void foo(std::function<void(double)>);
void foo(std::function<void(char const*)>);
然后,第二个重载foo
被明确选择:因为std::function
将F
定义为其外部接口,所以F
定义了哪些参数类型被传递到std::function
。然后,必须使用这些参数(参数类型)调用包装的函数对象。如果一个double
被传递到std::function
,它就不能被传递到一个使用std::string
的函数,因为没有转换double
->std::string
。
对于foo
的第一个重载,参数[](std::string){}
因此被认为不可调用std::function
。构造函数模板被停用,因此没有从[](std::string){}进行可行的转换
到std::function
。第一个重载将从用于解析调用(C)的重载集中删除,只留下第二个重载
请注意,上面的措辞有一点变化,原因是:有一个例外,如果std::function
的返回类型R
是void
,那么任何返回类型都会被接受(并丢弃)用于上述构造函数模板中的可调用项。例如,[]()->void{}和[]()->bool{}
可为std::function
调用。因此,以下情况会产生歧义:
void foo(std::function<void()>);
void foo(std::function<bool()>);
foo([]() -> bool {}); // ambiguous
类似地,在转换构造函数上使用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.);
}
#包括
#包括
结构foo
{
模板::类型>
傅(T)
{std::cout
巴(吨)
{std::cout标准规定,对于模板函数::函数(F)
重载类型F
必须可以用Args
中类型的参数调用。我假设这意味着标准要求构造函数必须是SFINAE(如果不能),这意味着您的调用是明确的。@简单:是的,这是有意义的,但我不认为转换为参数SFINAE失败会有助于重载解析。@Simple[res.on.required]“违反函数的Requires:段落中指定的前提条件会导致未定义的行为,除非函数的Throws:段落指定在违反前提条件时引发异常。”SFINAE失败在备注:部分中明确提到,例如:。[syserr.errcode.constructor]/7@lisyarus[参见前面的评论]…从技术上讲,它是UB(不是格式错误);libstdc++接受它并做正确的事情。我很困惑。为什么X(func1\u t f)
显然不应该是匹配的,而X(func2\u t f)
显然不匹配?在我的示例中没有重载lambda对象X([])([]){std::cout哪里可以看到重载lambda运算符()?重载的不是lambdas运算符。是构造函数重载了第一类对象参数。然后是其中一个(std::function”),然后是其中一个(std::function
)匹配闭包类型[]()
“在哪种意义上匹配?[]{}的闭包类型”
是一个独特的未命名类,与std::function
无关。后者有一个转换构造函数,它接受满足返回类型void
的Callable
要求且没有参数的任何参数表达式。我认为sfinae只处理函数的签名有效/无效,但她的e是从参数转换而来。它是否也涉及sfinae?我不明白为什么[res.on.required]
void foo(std::function<void(double)>);
void foo(std::function<void(char const*)>);
foo([](std::string){}) // (C)
void foo(std::function<void()>);
void foo(std::function<bool()>);
foo([]() -> bool {}); // ambiguous
#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.);
}
#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.);
}