c++ std::function 类型检查正确吗?
c++ std::function type cheking correct?
我希望使用 std::function 类型,以便在赋值时检查函数签名。但是我不明白这种情况下发生了什么
//g++ 5.4.0
#include <iostream>
#include <functional>
int f(int x) { std::cout << "//f:int->int\n"; return x; }
int g(double x) { std::cout << "//g:double->int\n"; return 1; }
int main()
{
std::function<int(int)> fct;
fct = f; fct(1);
fct = g; fct(1);
}
//trace
//
//f:int->int
//g:double->int
f 的行为是我想要的,但我认为 "fct=g;" 会导致编译时错误。
请问这个案例有什么亮点吗?
std::function
是灵活的并且在下面使用 type erasure
,所以如果你有带有签名 std::function<R(Args...)>
的 std::function
对象,它将接受任何 Callable
可以用 Args...
和 returns 类型调用 R
,
所以在你的情况下 std::function<int(int)>
,类型 int g(double);
的函数可以用类型 int
参数调用,编译器只会将 int
提升为 double
,
如果你运行这个代码
#include <iostream>
#include <functional>
int f(int x) { std::cout << x << " " << "//f:int->int\n"; return x; }
int g(double x) { std::cout << x << " " << "//g:double->int\n"; return 1; }
int main()
{
std::function<int(int)> fct;
fct = f; fct(1);
fct = g; fct(2.5);
}
你可以看到 fct
只会接受 int
然后编译器将它提升为 double
,所以在 fct(2.5);
的输出中它会打印 2 //g:double->int
而不是 2.5 //g:double->int
std::function
接受任何可以转换参数且 return 类型可转换的可调用对象。如果他们不是,你会得到一个编译错误。例如:
int h(double& x);
std::function<int(int)> fct;
fct = h; // <- compiler error
为了完成@gaurav 的回答,使用隐式转换完成场景(它确实让我感到惊讶,所以我为任何感兴趣的人添加它)
//g++ 5.4.0
#include <iostream>
#include <functional>
class C{
public :
int i;
C(int _i) : i(_i) { std::cout << "//C::C(int " << i << ")\n"; }
};
class D{
public :
int i;
D(int _i) : i(_i) { std::cout << "//D::D(int " << i << ")\n"; }
D(C c) : i(c.i) { std::cout << "//implicit conversion D::D(C " << c.i << ")\n"; }
};
int f(C c) { std::cout << "//f:C->int : "; return c.i; }
int g(D d) { std::cout << "//g:D->int : "; return d.i; }
int main()
{
{
std::cout << "//--- test implicit conversion\n";
C c(1);
D d(2);
d=c;
}
{
std::function<int(C)> fct; C c(1); D d(2);
std::cout << "//direct calls\n";
std::cout << f(c) << "\n";
// std::cout << "//" << f(d) << "\n"; // no conversion D->C provided by class C -->> error: could not convert ‘d’ from ‘D’ to ‘C’
std::cout << g(d) << "\n";
std::cout << g(c) << "\n"; // implicit conversion, then g:D->int
}
{
std::cout << "//case function:C->int\n";
std::function<int(C)> fct; C c(1); D d(2);
fct = f; std::cout << "//" << fct(c) << "\n";
//std::cout << "//" << fct(d) << "\n"; // no conversion D->C provided by class C -->> error: could not convert ‘d’ from ‘D’ to ‘C’
fct = g; std::cout << "//" << fct(c) << "\n";
//std::cout << "//" << fct(d) << "\n"; // no conversion D->C provided by class C -->> no match for call to ‘(std::function<int(C)>) (D&)’
}
{
std::cout << "//appels via function : D -> int\n";
std::function<int(D)> fct; C c(1); D d(2);
//fct = f; // conversion D->C would be meaningless to f
// -->> error: no match for ‘operator=’ (operand types are ‘std::function<int(D)>’ and ‘int(C)’)
fct = g; std::cout << "//" << fct(d) << "\n";
std::cout << "//" << fct(c) << "\n"; // implicit conversion, then g:D->int
}
}
//trace
//
//--- test implicit conversion
//C::C(int 1)
//D::D(int 2)
//implicit conversion D::D(C 1)
//C::C(int 1)
//D::D(int 2)
//direct calls
//f:C->int : 1
//g:D->int : 2
//implicit conversion D::D(C 1)
//g:D->int : 1
//case function:C->int
//C::C(int 1)
//D::D(int 2)
//f:C->int : //1
//implicit conversion D::D(C 1)
//g:D->int : //1
//appels via function : D -> int
//C::C(int 1)
//D::D(int 2)
//g:D->int : //2
//implicit conversion D::D(C 1)
//g:D->int : //1
我希望使用 std::function 类型,以便在赋值时检查函数签名。但是我不明白这种情况下发生了什么
//g++ 5.4.0
#include <iostream>
#include <functional>
int f(int x) { std::cout << "//f:int->int\n"; return x; }
int g(double x) { std::cout << "//g:double->int\n"; return 1; }
int main()
{
std::function<int(int)> fct;
fct = f; fct(1);
fct = g; fct(1);
}
//trace
//
//f:int->int
//g:double->int
f 的行为是我想要的,但我认为 "fct=g;" 会导致编译时错误。
请问这个案例有什么亮点吗?
std::function
是灵活的并且在下面使用 type erasure
,所以如果你有带有签名 std::function<R(Args...)>
的 std::function
对象,它将接受任何 Callable
可以用 Args...
和 returns 类型调用 R
,
所以在你的情况下 std::function<int(int)>
,类型 int g(double);
的函数可以用类型 int
参数调用,编译器只会将 int
提升为 double
,
如果你运行这个代码
#include <iostream>
#include <functional>
int f(int x) { std::cout << x << " " << "//f:int->int\n"; return x; }
int g(double x) { std::cout << x << " " << "//g:double->int\n"; return 1; }
int main()
{
std::function<int(int)> fct;
fct = f; fct(1);
fct = g; fct(2.5);
}
你可以看到 fct
只会接受 int
然后编译器将它提升为 double
,所以在 fct(2.5);
的输出中它会打印 2 //g:double->int
而不是 2.5 //g:double->int
std::function
接受任何可以转换参数且 return 类型可转换的可调用对象。如果他们不是,你会得到一个编译错误。例如:
int h(double& x);
std::function<int(int)> fct;
fct = h; // <- compiler error
为了完成@gaurav 的回答,使用隐式转换完成场景(它确实让我感到惊讶,所以我为任何感兴趣的人添加它)
//g++ 5.4.0
#include <iostream>
#include <functional>
class C{
public :
int i;
C(int _i) : i(_i) { std::cout << "//C::C(int " << i << ")\n"; }
};
class D{
public :
int i;
D(int _i) : i(_i) { std::cout << "//D::D(int " << i << ")\n"; }
D(C c) : i(c.i) { std::cout << "//implicit conversion D::D(C " << c.i << ")\n"; }
};
int f(C c) { std::cout << "//f:C->int : "; return c.i; }
int g(D d) { std::cout << "//g:D->int : "; return d.i; }
int main()
{
{
std::cout << "//--- test implicit conversion\n";
C c(1);
D d(2);
d=c;
}
{
std::function<int(C)> fct; C c(1); D d(2);
std::cout << "//direct calls\n";
std::cout << f(c) << "\n";
// std::cout << "//" << f(d) << "\n"; // no conversion D->C provided by class C -->> error: could not convert ‘d’ from ‘D’ to ‘C’
std::cout << g(d) << "\n";
std::cout << g(c) << "\n"; // implicit conversion, then g:D->int
}
{
std::cout << "//case function:C->int\n";
std::function<int(C)> fct; C c(1); D d(2);
fct = f; std::cout << "//" << fct(c) << "\n";
//std::cout << "//" << fct(d) << "\n"; // no conversion D->C provided by class C -->> error: could not convert ‘d’ from ‘D’ to ‘C’
fct = g; std::cout << "//" << fct(c) << "\n";
//std::cout << "//" << fct(d) << "\n"; // no conversion D->C provided by class C -->> no match for call to ‘(std::function<int(C)>) (D&)’
}
{
std::cout << "//appels via function : D -> int\n";
std::function<int(D)> fct; C c(1); D d(2);
//fct = f; // conversion D->C would be meaningless to f
// -->> error: no match for ‘operator=’ (operand types are ‘std::function<int(D)>’ and ‘int(C)’)
fct = g; std::cout << "//" << fct(d) << "\n";
std::cout << "//" << fct(c) << "\n"; // implicit conversion, then g:D->int
}
}
//trace
//
//--- test implicit conversion
//C::C(int 1)
//D::D(int 2)
//implicit conversion D::D(C 1)
//C::C(int 1)
//D::D(int 2)
//direct calls
//f:C->int : 1
//g:D->int : 2
//implicit conversion D::D(C 1)
//g:D->int : 1
//case function:C->int
//C::C(int 1)
//D::D(int 2)
//f:C->int : //1
//implicit conversion D::D(C 1)
//g:D->int : //1
//appels via function : D -> int
//C::C(int 1)
//D::D(int 2)
//g:D->int : //2
//implicit conversion D::D(C 1)
//g:D->int : //1