C ++自动构造函数调用

时间:2015-11-16 16:56:28

标签: c++ templates c++11 casting

假设我们有一个原始的C风格字符串"test"。我们可以声明一个这样的函数:

void printText(std::string textToPrint){
   std::cout << textToPrint << "\n";
}

我们可以通过以下方式调用它:

printText("test");

这应该是完全正常的,因为参数是一个对象,而不是一个引用,因此应该在调用函数`printText()'时创建像std::string("test")这样的临时对象。

现在,我有一个以下模板:

template <typename T>
T checkMe(Proxy<T> arg){
    std::cout << arg() << std::endl;
    return arg();
}

其中Proxy类声明如下:

template <typename T>
class Proxy{
public:
    Proxy(std::function<T&()> caller);
    Proxy(std::shared_ptr<T> dataPtr);
    T& operator()();
private:
    std::function<T&()> m_functional;
    std::shared_ptr<T> m_data;
};

它的目的是使用两种对象类型调用一些函数: 一个是数据的shared_ptr,另一个是功能对象,它返回这种类型的数据。

现在,当我想调用函数checkMe时,会发生错误,我不知道为什么会出现以及如何解决它。一件事是:

getMe(std::make_shared<int>(255));

这在我看来应该完全正常,因为Proxy的构造函数将shared_ptr作为参数并基于它创建自己。但这会给编译器的演绎错误。然而,当我调用这样的函数时:

getMe<int>(std::make_shared<int>(255));

现在好了。我不知道为什么编译器不能自己推断出类型。

第二种情况是用功能对象调用它:

getMe<int>(std::bind(getNumberMult,5,6));

getNumberMult的定义如下:

int xy;
int& getNumberMult(int x, int y){
    return xy = x*y;
}

此处发生转换错误。有人可以指定是否可能以及如何实现给定代码的期望行为并解释我对该机制的理解有什么问题?我想使用以下代码:

getMe(std::make_shared<int>(300));
getMe(std::bind(getNumberMult, 6, 7));

编译器错误:

使用时

getMe<int>(std::bind(getNumberMult, 5, 6));

path/to/file:36: error: C2664: 'T getMe<int>(DataProxy<T>)' : cannot convert argument 1 from 'std::_Bind<true,int &,int &(__cdecl *const )(int,int),int,int>' to 'DataProxy<int>'
with
[
    T=int
]

2 个答案:

答案 0 :(得分:2)

使用T checkMe(Proxy<T> arg)arg应为Proxy<T>(或从中继承)。

编译器没有检查测试每个Proxy<T>可以从给定参数构造的无限可能性。

答案 1 :(得分:0)

所以我现在知道为什么会这样,我该怎么做才能解决它。

考虑以下对象:

struct Test{
    Test(std::string someString){}
};

所以我们需要std :: string来构造这个类的对象。

我们可以通过以下方式明确创建std::string

int main(){
    Test someVariable("someRawString");
}

它会起作用而且完全没问题。发动机罩发生了什么:

  • 编译器符合创建Test
  • 对象的指令
  • 它看到,给定的参数不是Constructor
  • 所要求的类型
  • 因为事实,所需的参数是一个值,而不是一个引用(const引用也可以)它创建类型std::string的临时对象并将此临时对象传递给构造函数
  • 已成功创建对象。

现在让我们考虑一下功能:

void someTestFunction(Test someTest){}

它需要Test类型的对象,它由std::string

构成

鉴于此,以下列方式调用此函数应该没问题:

someTestFunction("someRawText");

但它并不好。这给了我们转换参数的错误。原因很简单:当将参数传递给函数时,C ++只允许转换一步。所以编译器可以:

  • 将原始字符串转换为std::string
  • 使用Test
  • 创建std::string个对象

但它不能:

  • 将原始字符串转换为std::string
  • std::string投放到Test(转化次数过多)
  • 使用Test
  • 调用函数

给定代码发生了完全相同的事情。为了使它工作,我们应该使用:

getMe<int>(std::make_shared<int>(300));
getMe<int>(std::function<int&()>(std::bind(getNumberMult, 6, 7)));

为什么会这样?

std::make_shared<int>的返回类型为std::shared_ptr<int>,因此无需转换即可调用函数。

std::bind...的返回类型与std::function不同,它有自己的实现定义的返回类型。这就是为什么这里需要第二次演员,这是C ++不允许的。当我们明确地转换它时,只需要一个隐式转换,一切正常。