是否可以将对象的类型存储在地图中以用于强制转换

时间:2016-08-04 17:31:00

标签: c++ c++11 decltype

对于令人困惑的标题感到抱歉,因为我不确定如何说出来。 我想要做的是基本上转换为将从地图动态检索的类型。 (地图不会有实例,但如果可能的话会有类型)

请允许我用一个例子来解释。 假设我有一个名为baseFoo

的基类
class baseFoo
{
}

然后我有两个不同的类继承自baseFoo,名为derFooAderFooB

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)

现在我的问题是,如果这样的机制可能,我的陈述会是什么样的?

2 个答案:

答案 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::tupleSigs*根据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