对于令人困惑的标题感到抱歉,因为我不确定如何说出来。 我想要做的是基本上转换为将从地图动态检索的类型。 (地图不会有实例,但如果可能的话会有类型)
请允许我用一个例子来解释。
假设我有一个名为baseFoo
class baseFoo
{
}
然后我有两个不同的类继承自baseFoo,名为derFooA
和derFooB
class derfooA : public baseFoo
{
}
,同样适用于derfooB
class derfooB : public baseFoo
{
}
现在我想知道我是否只能在地图中存储一个类型(不是类型的实例 - 只是一个变量类型),就像这样
//STATEMENT A:
std::map<std::string , baseFoo> myMap= {{"derfooA",derfooA}, {"derfooB", derfooB}};
然后我想做这样的事情:
说我有一个baseFoo
ptr,我想基于字符串将ptr DownCast为特定类型。所以我可以这样做:
std::string str = "derfooA";
derfooA* dfoo = dynamic_cast<myMap[str]>(baseFoo_ptr)
现在我的问题是,如果这样的机制可能,我的陈述会是什么样的?
答案 0 :(得分:2)
template<class...Ts>
struct types { using type=types; };
这是一堆类型。
template<class T>struct tag_t{constexpr tag_t(){}; using type=T;};
template<class T>constexpr tag_t<T> tag{};
这是一个类型标记。
template<class T, class U>
T* tag_dynamic_cast( tag_t<T>, U* u ) {
return dynamic_cast<T*>(u);
}
template<class T, class U>
T& tag_dynamic_cast( tag_t<T>, U& u ) {
return dynamic_cast<T&>(u);
}
这使您可以根据标记调度动态强制转换。
template<class F, class Sig>
struct invoker;
template<class F, class R, class...Args>
struct invoker<F, R(Args...)> {
R(*)(void*, Args...) operator()() const {
return [](void* ptr, Args...args)->R {
return (*static_cast<F*>(ptr))(std::forward<Args>(args)...);
};
}
};
template<class F, class...Sigs>
std::tuple<Sigs*...> invokers() {
return std::make_tuple( invoker<F, Sigs>{}()... );
}
所以在这一点上,我们有一个指向函数的指针元组,这些函数将调用给定的对象F
类型,每个签名都有一组签名Sigs
。
我们接下来会编写一个dipatcher,根据Sigs
的{{1}} Sigs...
std::tuple
来Sigs*
根据void*
选择“正确”types<...>
{1}}第一个论点。
现在我们采用您要支持的std::unique_ptr<void, void(*)(void*)>
类型转换为。我们使用它来生成一个类型擦除类,它在tag_t<x>
中存储传入的lambda。我们支持的签名为x
,其中types<x...>
因void*
中的类型而异。
这是您的动态调度员。
我们大部分都在那里。接下来,我们构建一个需要动态调度程序和tag_t<x>
的东西,并使用tag_t<x>
调用它。它会擦除//STATEMENT A:
std::map<std::string , helper<derFooA, derFooB>> myMap=
{{"derfooA",tag<derfooA>}, {"derfooB", tag<derfooB>}};
myMap[str]( [&](auto&& tag) {
auto* dfoo = tag_dynamic_cast(tag, baseFoo_ptr);
} );
它将调用动态调度程序,因此接口不会公开它。在这一点上它基本上是std函数的绑定器,很容易。
public class WebkitCookieManagerProxy extends CookieManager implements CookieJar {
private android.webkit.CookieManager webkitCookieManager;
private static final String TAG = WebkitCookieManagerProxy.class.getSimpleName();
public WebkitCookieManagerProxy() {
this(null, null);
}
WebkitCookieManagerProxy(CookieStore store, CookiePolicy cookiePolicy) {
super(null, cookiePolicy);
this.webkitCookieManager = android.webkit.CookieManager.getInstance();
}
@Override
public void put(URI uri, Map<String, List<String>> responseHeaders)
throws IOException {
// make sure our args are valid
if ((uri == null) || (responseHeaders == null))
return;
// save our url once
String url = uri.toString();
// go over the headers
for (String headerKey : responseHeaders.keySet()) {
// ignore headers which aren't cookie related
if ((headerKey == null)
|| !(headerKey.equalsIgnoreCase("Set-Cookie2") || headerKey
.equalsIgnoreCase("Set-Cookie")))
continue;
// process each of the headers
for (String headerValue : responseHeaders.get(headerKey)) {
webkitCookieManager.setCookie(url, headerValue);
}
}
}
@Override
public Map<String, List<String>> get(URI uri,
Map<String, List<String>> requestHeaders) throws IOException {
// make sure our args are valid
if ((uri == null) || (requestHeaders == null))
throw new IllegalArgumentException("Argument is null");
// save our url once
String url = uri.toString();
// prepare our response
Map<String, List<String>> res = new java.util.HashMap<String, List<String>>();
// get the cookie
String cookie = webkitCookieManager.getCookie(url);
// return it
if (cookie != null) {
res.put("Cookie", Arrays.asList(cookie));
}
return res;
}
@Override
public CookieStore getCookieStore() {
// we don't want anyone to work with this cookie store directly
throw new UnsupportedOperationException();
}
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
HashMap<String, List<String>> generatedResponseHeaders = new HashMap<>();
ArrayList<String> cookiesList = new ArrayList<>();
for(Cookie c: cookies) {
// toString correctly generates a normal cookie string
cookiesList.add(c.toString());
}
generatedResponseHeaders.put("Set-Cookie", cookiesList);
try {
put(url.uri(), generatedResponseHeaders);
} catch (IOException e) {
Log.e(TAG, "Error adding cookies through okhttp", e);
}
}
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
ArrayList<Cookie> cookieArrayList = new ArrayList<>();
try {
Map<String, List<String>> cookieList = get(url.uri(), new HashMap<String, List<String>>());
// Format here looks like: "Cookie":["cookie1=val1;cookie2=val2;"]
for (List<String> ls : cookieList.values()) {
for (String s: ls) {
String[] cookies = s.split(";");
for (String cookie : cookies) {
Cookie c = Cookie.parse(url, cookie);
cookieArrayList.add(c);
}
}
}
} catch (IOException e) {
Log.e(TAG, "error making cookie!", e);
}
return cookieArrayList;
}
虽然lambda将针对每个派生类型进行实例化,但唯一一个将运行的是与地图中存储的值匹配的那个。
你会注意到你被困在lambda中。是的。除了作为运行时状态之外,您不能“泄漏”实际类型信息。
现在,赔率是你真正的问题有一个更容易的解决方案。但这是如何做到这一点的路线图。我自己写的时间太长了。
答案 1 :(得分:0)
将类型存储在实例中,如下所示:
class baseFoo
{
public:
class enum eClass
{
a,
b,
} myType;
baseFoo( eClass type )
: myType( type )
{}
eClass getType() { return myTpe; }|
};
class derfooA : public baseFoo
{
public:
derfooA()
: baseFoo( baseFoo::eClass::a )
{}
};
...
baseFoo * ptr;
...
switch( ptr->getType() ) {
case baseFoo::eClass::a:
... do something