C++ std::function类型检查是否正确?

3

我希望使用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;"会导致编译时错误。

请问这种情况有什么解释吗?

3个回答

2

std::function接受任何可调用对象,只要它们的参数可以转换并且返回类型是可转换的。如果不满足条件,则会导致编译错误。例如:

int h(double& x);

std::function<int(int)> fct;
fct = h; // <- compiler error

1

std::function 是灵活的并且在底层使用了类型擦除,因此如果你有一个带有签名 std::function<R(Args...)> 的对象,它将接受任何可调用的 Callable,该可调用的函数可以使用类型 Args... 调用并返回类型 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

感谢@gaurav。如果我理解正确的话,也许f应该是int->double,g应该是double->double,而fct应该是int->double。所以fct=g "强制"第一个参数转换为int(测试确实证实了这一点,但我不是100%确定,因为在你的例子中g返回一个int..) - chetzacoalt
@chetzacoalt,由于代码中的每个返回类型都是int,所以返回类型不应该有影响。当代码调用fct(2.5)时,由于fct ::operator()仅接受int,因此它将2.5转换为2。 - Gaurav Dhiman

0

为了补充@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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接