Template-Driven Resource Manager, Compiler Problem

Started by
6 comments, last by Aprosenf 19 years, 4 months ago
Hi folks, I am trying to implement a template driven resource manager. I've got sample sources from Sam Lantinga and are about to change some things. Unfortunately these changes produce some warning I didn't get rid of yet, maybe you've got an idea: A little code-snippet

template<class T> class CResourceCache
{
    public:
        CResourceCache( void )
        {
            m_vCache.clear();
        }    
        
    protected:
        typedef struct Cache
        {
            string strName;
            T *data;
        };            

        vector<Cache> m_vCache;             
};    

As you can see, I am referencing the template class within the Cache struct which I am trying to create an stl vector of. My compiler now is concerned about that vector<Cache> statement and says that implicit typenames are deprecated: [Warning] implicit typename is deprecated, please see the documentation for details But whatever I did to that statement, I was not able to resolve this problem. Does anyone of you know the solution? Regards, T.
Advertisement
Why are you typedefing your struct to an empty name? As it is I can compile your code under gcc, but it generates an error under Borland C++ because of the typedef. Removing the typedef enables me to compile it with no errors or warnings under both gcc and Borland C++.

Enigma
You are right! Thanks! Removing the typedef solved part of the problem.
But now there's still another of the same type.

Here a part, I didn't post before:

The following snippet is taken out of the class as shown in the post above
(...)protected:struct Cache{    string strName;    T *data;};            vector<Cache> m_vCache;             T *Find( const string strName ) {    T *data;                for( vector<Cache>::iterator itrCache = m_vCache.begin(); itrCache != m_vCache.end(); ++itrCache )    {        (...)    }}


On the vector<Cache>::iterator above, I am getting the same warning about deprecated implicit typenames...
Why are you using vector for this? Shouldn't std::map (or hashmap) be much better option. It gets rid of 'Cache' structure and gives you O(logN) or O(1) search time.
You should never let your fears become the boundaries of your dreams.
Hm. You got me.

For a moment, I thought: Because a map is slower than a vecotr due to all of these string comparisons...

Then, something popped into my mind: I am doing exactly the same, except that my code won't be as optimized for this as a map already is... plus: it's kind of bloated that way.

So you're right. I'll try using a map.
Thanks for the hint!

T.

But: Can you explain though, why I am getting the warning and how to fix this?
choice 1: using a vector of pair of string & smart pointer to resource:

#include <boost\smart_ptr.hpp>#include <utility>#include <algorithm>#include <string>#include <vector>template<class Resource>struct resource_mgr {	typedef boost::shared_ptr<Resource> res_ptr;    typedef std::pair<std::string, res_ptr> res_pair;    typedef std::vector< res_pair > res_vec;	typedef typename res_vec::iterator res_itr;	typedef typename res_vec::const_iterator const_res_itr;private:    res_vec resources;	struct res_find {		const std::string& res_name;		res_find(const std::string& _res_name): res_name(_res_name) {}		bool operator()(const res_pair& r) const {			return r.first == res_name;		}	};     resource_mgr(const resource_mgr<Resource>&);     resource_mgr<Resource>& operator=(const resource_mgr<Resource>&);public:	static const res_ptr NULL_RESOURCE;	resource_mgr(typename res_vec::size_type num_to_cache = 0) {		resources.reserve(num_to_cache);	}	bool add_resource(const res_pair& f) {		if(std::find_if(resources.begin(), resources.end(), res_find(f.first)) != resources.end())			return false;		else {			resources.push_back(f);			return true;		}	}	const res_ptr& get_resource(const std::string& s) const {		const_res_itr itr = std::find_if(resources.begin(), resources.end(), res_find(s));		if(itr != resources.end()) {			return itr->second;		} else			return res_ptr();	}	res_ptr get_resource(const std::string& s) {		res_itr itr = std::find_if(resources.begin(), resources.end(), res_find(s));		if(itr != resources.end()) {			return itr->second;		} else			return res_ptr();	}        };template < typename Resource >const typename resource_mgr<Resource>::res_ptr resource_mgr<Resource>::NULL_RESOURCE;#include <iostream>struct foo {	int i;	foo(int j): i(j) {}};int main() {	typedef resource_mgr<foo> foo_res_mgr;	foo_res_mgr m(1);	m.add_resource(std::make_pair("foo", new foo(10)));	foo_res_mgr::res_ptr r;		if((r = m.get_resource("foo")) != foo_res_mgr::NULL_RESOURCE)		std::cout << r->i << '\n';	else		std::cout << "resource not found\n";	}


choice 2: using STL extension hash_map of strings to smart pointer to resource:
#include <boost\smart_ptr.hpp>#include <string>#include <hash_map>template<class Resource>struct resource_mgr {	typedef boost::shared_ptr<Resource> res_ptr;	typedef stdext::hash_map< std::string, res_ptr > res_vec;	typedef typename res_vec::iterator res_itr;	typedef typename res_vec::const_iterator const_res_itr;private:    res_vec resources;	resource_mgr(const resource_mgr<Resource>&);    resource_mgr<Resource>& operator=(const resource_mgr<Resource>&);public:	resource_mgr(): resources() {}	const res_ptr& operator[](const std::string& n) const {		return resources[n];	}	res_ptr& operator[](const std::string& n) {		return resources[n];	}};#include <iostream>struct foo {	int i;	foo(int j): i(j) {}};int main() {	typedef resource_mgr<foo> foo_res_mgr;	foo_res_mgr m;	foo_res_mgr::res_ptr r(new foo(10));	m["foo"] = r;	std::cout << m["foo"]->i << '\n';}


choice 3: using hash_map of strings to boost::any (this would be waste of time doing for a resource manager)

#include <boost\smart_ptr.hpp>#include <boost\any.hpp>#include <string>#include <hash_map>struct resource_mgr {	typedef stdext::hash_map< std::string, boost::any > res_vec;	typedef res_vec::iterator res_itr;	typedef res_vec::const_iterator const_res_itr;private:    res_vec resources;	resource_mgr(const resource_mgr&);    resource_mgr& operator=(const resource_mgr&);public:	resource_mgr(): resources() {}	/*const boost::any& operator[](const std::string& n) const {		return resources[n];	}*/	boost::any& operator[](const std::string& n) {		return resources[n];	}};#include <iostream>struct foo {	int i;	foo(int j): i(j) {}};int main() {	resource_mgr m;		m["foo"] = foo(20);	std::cout << boost::any_cast<foo>(m["foo"]).i << '\n';}


most definitely more choices available.

references: boost library
Quote:Original post by TroneX
Hm. You got me.

For a moment, I thought: Because a map is slower than a vecotr due to all of these string comparisons...

Then, something popped into my mind: I am doing exactly the same, except that my code won't be as optimized for this as a map already is... plus: it's kind of bloated that way.

So you're right. I'll try using a map.
Thanks for the hint!

T.

But: Can you explain though, why I am getting the warning and how to fix this?


You have to do:

typename vector<Cache>::iterator

because Cache is dependent on a template parameter. This means that even if you have vector's default definition included already (you can potentially even only have its declaration), the instantiated template may resolve to a specialization that has the iterator member defined to be anything, such as a datamember instead of a type, which makes it impossible to address without ambiguity in the template definition since the information can't normally be determined until the template is instantiated. It is impossible to know if vector<Cache>::iterator is a type or another form of member (datamember, memberfunction, etc) since that can't be known until you instantiate it. Using typename tells the compiler in advance that vector<Cache>::iterator should resolve to a type, otherwise it should result in error.
You could try

vector< CResourceCache<T>::Cache >::iterator

This topic is closed to new replies.

Advertisement