我正在转换大型代码以使用自定义共享指针而不是原始指针。我有重载分辨率的问题。考虑这个例子:
#include <iostream>
struct A {};
struct B : public A {};
void f(const A*)
{
std::cout << "const version\n";
}
void f(A*)
{
std::cout << "non-const version\n";
}
int main(int, char**)
{
B* b;
f(b);
}
此代码正确写入“非const版本”,因为qualification conversions在隐式转换序列的排名中起作用。现在看一下使用shared_ptr的版本:
#include <iostream>
#include<memory>
struct A {};
struct B : public A {};
void f(std::shared_ptr<const A>)
{
std::cout << "const version\n";
}
void f(std::shared_ptr<A>)
{
std::cout << "non-const version\n";
}
int main(int, char**)
{
std::shared_ptr<B> b;
f(b);
}
此代码无法编译,因为函数调用不明确。
我知道user-defined deduction-guide将是一个解决方案,但在Visual Studio中仍然不存在。
我正在使用regexp转换代码,因为有数千个此类调用。正则表达式无法区分与const版本匹配的调用与与非const版本匹配的调用。使用共享指针时是否可以更好地控制重载决策,并避免手动更改每个调用?当然我可以.get()原始指针并在调用中使用它但我想完全消除原始指针。
答案 0 :(得分:1)
你可以引入额外的重载来为你做出爆燃:
template <class T>
void f(std::shared_ptr<T> a)
{
f(std::static_pointer_cast<A>(a));
}
template <class T>
void f(std::shared_ptr<const T> a)
{
f(std::static_pointer_cast<const A>(a));
}
您还可以使用std::enable_if
来限制非const
T
的第一次重载,和/或将T
的两次重载限制为A
。 1}}。
这是如何运作的:
某些std::shared_ptr<X>
的{{1}}不是X
也不是A
(const A
或B
)。如果没有模板重载,编译器必须选择将此const B
转换为std::shared_ptr<X>
或std::shared_ptr<A>
。两者都是排名相同的良好转换(两者都是用户定义的转换),因此存在歧义。
添加模板重载后,有四种参数类型可供选择(让我们分析std::shared_ptr<const A>
案例):
X = const B
std::shared_ptr<A>
std::shared_ptr<const A>
从第一个模板实例化,std::shared_ptr<const B>
。T = const B
从第二个模板设置std::shared_ptr<const B>
。显然,类型3和4优于1和2,因为它们根本不需要转换。因此将选择其中一个。
类型3和4本身是相同的,但是随着模板的重载分辨率的增加,还会出现其他规则。即,一个更专业的模板&#34; (更多的非模板签名匹配)优先于一个较不专业的。由于过载4在签名的非模板部分(T = B
之外)中有const
,因此它更专业,因此被选中。
没有规则说&#34;模板更好。&#34;事实上,恰恰相反:当模板和非模板具有相同的成本时,非模板是首选。这里的诀窍是模板的成本较小(不需要转换)比非模板(需要用户定义的转换)。
答案 1 :(得分:0)
标签调度可以解决问题 它遵循一个最小的工作示例:
import pandas as pd
from pandas_datareader import data, wb
import datetime
start = datetime.datetime(2016,1,1)
end = datetime.date.today()
apple = data.DataReader(input("Please Input the name of the Ticker:\n"), "yahoo", start, end)
type(apple)
apple.head()
Please Input the name of the Ticker:
AAPL
Open High Low Close Volume Adj Close
Date
2016-01-04 102.610001 105.370003 102.000000 105.349998 67649400 103.057063
2016-01-05 105.750000 105.849998 102.410004 102.709999 55791000 100.474523
2016-01-06 100.559998 102.370003 99.870003 100.699997 68457400 98.508268
2016-01-07 98.680000 100.129997 96.430000 96.449997 81094400 94.350769
2016-01-08 98.550003 99.110001 96.760002 96.959999 70798000 94.849671
如您所见,您已经拥有了创建标记所需的内容:存储的指针。
无论如何,你不必得到它并在呼叫点传递它。相反,通过使用中间函数模板,您可以将其用作在内部调度调用的类型。如果您不想使用它,您甚至不必为参数命名。