Template question...

This is a discussion on Template question... within the C++ Programming forums, part of the General Programming Boards category; I am wondering if the following is even possible, if so what am I doing wrong? Code: #include <boost/ptr_container/ptr_vector.hpp> #include ...

  1. #1
    Registered User
    Join Date
    Nov 2005
    Posts
    673

    Template question...

    I am wondering if the following is even possible, if so what am I doing wrong?
    Code:
    #include <boost/ptr_container/ptr_vector.hpp>
    #include <boost/any.hpp>
    class VarList
    {
    private:
        boost::ptr_vector<boost::any> variables;
    
    public:
        VarList(){};
        ~VarList(){};
    
        int NewVar(boost::any* var)
        {
            variables.push_back(var);
            return variables.size()-1;
        };
    
        template<typename valtype>
        valtype GetVar(size_t index);
    };
    
    template<> int VarList::GetVar<int>(size_t index)
    {
        return boost::any_cast<int>(variables.at(index));
    };
    
    template<> std::string VarList::GetVar<std::string>(size_t index)
    {
        return boost::any_cast<std::string>(variables.at(index));
    }
    
    #include <iostream>
    #include <string>
    
    int main()
    {
        VarList test;
        test.NewVar(new boost::any(100));
        test.NewVar(new boost::any(std::string("Test String")));
    
        std::cout << "Var[0] = " << test.GetVar(0) << std::endl;
        std::cout << "Var[1] = " << test.GetVar(1) << std::endl;
        system("pause");
        return 0;
    }
    Errors
    Code:
    1>------ Build started: Project: VariaFunctionScript, Configuration: Debug Win32 ------
    1>Compiling...
    1>VariaFunctionScript.cpp
    1>c:\documents and settings\cody doughty\my documents\visual studio 2008\projects\variafunctionscript\variafunctionscript\variafunctionscript.cpp(44) : error C2783: 'valtype VarList::GetVar(size_t)' : could not deduce template argument for 'valtype'
    1>        c:\documents and settings\cody doughty\my documents\visual studio 2008\projects\variafunctionscript\variafunctionscript\variafunctionscript.cpp(22) : see declaration of 'VarList::GetVar'
    1>c:\documents and settings\cody doughty\my documents\visual studio 2008\projects\variafunctionscript\variafunctionscript\variafunctionscript.cpp(45) : error C2783: 'valtype VarList::GetVar(size_t)' : could not deduce template argument for 'valtype'
    1>        c:\documents and settings\cody doughty\my documents\visual studio 2008\projects\variafunctionscript\variafunctionscript\variafunctionscript.cpp(22) : see declaration of 'VarList::GetVar'
    1>Build log was saved at "file://c:\Documents and Settings\Cody Doughty\My Documents\Visual Studio 2008\Projects\VariaFunctionScript\VariaFunctionScript\Debug\BuildLog.htm"
    1>VariaFunctionScript - 2 error(s), 0 warning(s)
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
    Thank you very much for any assistance.

  2. #2
    Banned master5001's Avatar
    Join Date
    Aug 2001
    Location
    Visalia, CA, USA
    Posts
    3,685
    You need to declare your template class as a template, and define its arguments.

    Example:
    Code:
    #include <boost/ptr_container/ptr_vector.hpp>
    #include <boost/any.hpp>
    
    template<typename Type>
    class VarList
    {
    private:
        boost::ptr_vector<boost::any> variables;
    
    public:
        VarList(){};
        ~VarList(){};
    
        int NewVar(boost::any* var)
        {
            variables.push_back(var);
            return variables.size()-1;
        };
    
        template<typename valtype>
        valtype GetVar(size_t index);
    };
    
    template<typename Type> int VarList::GetVar<int>(size_t index)
    {
        return boost::any_cast<int>(variables.at(index));
    };
    
    template<typename Type> std::string VarList::GetVar<std::string>(size_t index)
    {
        return boost::any_cast<std::string>(variables.at(index));
    }
    
    #include <iostream>
    #include <string>
    
    int main()
    {
        VarList test<std::string>;
        test.NewVar(new boost::any(100));
        test.NewVar(new boost::any(std::string("Test String")));
    
        std::cout << "Var[0] = " << test.GetVar(0) << std::endl;
        std::cout << "Var[1] = " << test.GetVar(1) << std::endl;
        system("pause");
        return 0;
    }
    boost::any is supposed to function as something more variable, by the way. Thus using a template in conjunction with boost::any sort of demotes the potential of boost::any.

  3. #3
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,046
    I just thought I should mention -- a lot of your semicolons are unnecessary.
    Code:
    #include <boost/ptr_container/ptr_vector.hpp>
    #include <boost/any.hpp>
    class VarList
    {
    private:
        boost::ptr_vector<boost::any> variables;
    
    public:
        VarList(){}; // unnecessary
        ~VarList(){}; // unnecessary
    
        int NewVar(boost::any* var)
        {
            variables.push_back(var);
            return variables.size()-1;
        }; // unnecessary
    
        template<typename valtype>
        valtype GetVar(size_t index);
    };
    
    template<> int VarList::GetVar<int>(size_t index)
    {
        return boost::any_cast<int>(variables.at(index));
    }; // unnecessary
    
    template<> std::string VarList::GetVar<std::string>(size_t index)
    {
        return boost::any_cast<std::string>(variables.at(index));
    }
    There's nothing actually wrong with putting in extra semicolons, but they are after all spurious, and why type extra if you don't have to?

    The general rule is: you only need a semicolon after a closing curly brace if the brace terminated a class/struct/enum/union declaration or an initializer.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  4. #4
    Banned master5001's Avatar
    Join Date
    Aug 2001
    Location
    Visalia, CA, USA
    Posts
    3,685
    Before you say: "dwks, you anally retentive, pedantic bastard!" Realize that its easy to make certain deadly mistakes that can break stuff if you get too free with semicolons. Some of which the compiler will mention, others not quite so much.

    Example:
    Code:
    #include <istream>;
    
    int main();
    {
      int i;
    
      for(i = 0; i < 25; i++);
      {
        std::cout << i;
      };
    
      return 0;
    };

  5. #5
    Registered User
    Join Date
    Nov 2005
    Posts
    673
    I have just kinda got used to putting a ';' after any closing curly brace.

    boost::any is supposed to function as something more variable, by the way. Thus using a template in conjunction with boost::any sort of demotes the potential of boost::any.
    I am confused by your statement. boost::any has to be explicitly converted correct?
    Doing this everywhere would be kinda annoying, and would require knowing the type.
    Code:
        std::cout << "Var[0] = " << boost::any_cast<int>(test.GetVar(0)) << std::endl;
        std::cout << "Var[1] = " << boost::any_cast<std::string>(test.GetVar(1)) << std::endl;
    Thus a template can take that requirement of knowledge out of the picture. Allowing myself to focus on other details correct?

    edit: Master the modification you provided does not compile either.
    Last edited by Raigne; 10-11-2008 at 04:41 PM.

  6. #6
    Banned master5001's Avatar
    Join Date
    Aug 2001
    Location
    Visalia, CA, USA
    Posts
    3,685
    Is that the objective behind the template? And what you are saying about boost::any is right. What I am saying is that if you are typing something that can change types at will, then you are limiting what it can do.

    It sounds to me like I misunderstood what you are wanting. You want it to just automatically change types implicitly, right?

  7. #7
    Registered User
    Join Date
    Nov 2005
    Posts
    673
    I am just trying to create a VarList class that does not have to have
    GetStringVar(index)
    GetIntVar(index)
    GetVoidVar(index)
    etc
    etc

    Maybe there is a different way to go about this.
    The types I will support are
    char* or (std::string) for raw data
    int
    double
    function pointer

    If there is a better way to go about this then by all means enlighten me please.

    edit:
    but I was also leaning toward a more dynamic list. So I don't have to change the executable to add another type.

  8. #8
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,046
    C++ is a strongly-typed language, so I can't really see a way that you could have one function that returns a string or an int or whatever. Maybe it's possible with Boost, I don't know.

    What you could do is have an object that can be of any type (or just a string or int or whatever), and pass that around. Then to print a meta-object, for example, you could use something like
    Code:
    switch(object.type) {
    case TYPE_INT:
        cout << object.get_data_as_int();
        break;
    case TYPE_STRING:
        cout << object.get_data_as_string();
        break;
    }
    I don't know, it doesn't seem like a very good solution to me. Might want to wait to see what others have to say.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  9. #9
    Registered User
    Join Date
    Nov 2005
    Posts
    673
    Okay, I came up with this. Not sure that it will work, but a little more sensible I think.
    It is by no means complete, but figured before i do anything else I would see what you all thought.
    Code:
    #include <iostream>
    #include <string>
    #include <map>
    #include <windows.h>
    #include <sstream>
    
    unsigned ElfHash( const std::string& key )
    {
    	unsigned h = 0, g;
    	for (unsigned i = 0; i < key.length(); i++ )
    	{
    		h = ( h << 4 ) + key.at(i);
    		g = h & 0xf0000000L;
    		if ( g != 0 )
    			h ^= g >> 24;
    		h &= ~g;
    	}
    	return h;
    }
    
    class ScriptFunction
    {
    public:
    	ScriptFunction(const ScriptFunction& copy)
    	{
    		this->Param1ID = copy.Param1ID;
    		this->Param2ID = copy.Param2ID;
    		this->Param3ID = copy.Param3ID;
    		this->ReturnID = copy.ReturnID;
    		this->Function.Func = copy.Function.Func;
    	};
    	//Name in the script
    	std::string ScriptName;
    	//The id of the function(same as the index in function list)
    	UINT FunctionID;
    
    	enum ID
    	{
    		INT,
    		FLOAT,
    		STRING
    	};
    	ID ReturnID;
    	ID Param1ID;
    	ID Param2ID;
    	ID Param3ID;
    	struct func
    	{
    		union Var
    		{
    			UINT		Int;
    			double		Float;
    			char*       String;
    		};
    		Var(*Func)(Var,Var,Var);
    	};
    	func Function;
    };
    
    class ScriptFunctionList
    {
    private:
    	std::map<UINT,ScriptFunction*> Functions;
    
    public:
    	ScriptFunctionList()
    	{}
    	~ScriptFunctionList()
    	{}
    
    	//Pushes a function onto stack(copy), and returns ID
    	UINT PushFunction(ScriptFunction& new_function)
    	{
    		ScriptFunction* newFunc = 0;
    		newFunc = new ScriptFunction(new_function);
    
    
    		if ( newFunc )
    		{
    			//IDs are made by hashing the memory location of the ScriptFunction
    			//Copy new function the add
    			std::stringstream ss;
    			ss << &new_function;
    			UINT tID = ElfHash(ss.str());
    			newFunc->FunctionID = tID;
    			Functions[tID] = newFunc;
    			return tID;
    		}
    		else
    		{
    			MessageBoxA(0,"ScriptFunctionList Error.\r\nCould not allocate memory.","Error",MB_OK|MB_ICONERROR);
    			return 0;
    		}
    	}
    
    	//This will release all functions that were added
    	void Free()
    	{
    		std::map<UINT,ScriptFunction*>::iterator it = Functions.begin();
    		for ( ; it != Functions.end(); ++it )
    		{
    			delete (*it).second;
    			(*it).second = 0;
    		}
    	}
    };
    I am thinking that this will provide a much more solid function layout. It is the only way I could think to do this. The hash shouldn't replicate values, since the memory address for each function has to be different. Hopefully I am thinking right on this.

    edit: modified the above code
    Last edited by Raigne; 10-11-2008 at 08:41 PM.

  10. #10
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,618
    You realize that in your first post, you got a compile error because GetVar had a template argument for a type that you never specify.
    Since no arguments for the function references this type, the compiler is in dark of what it could be. In that case, you need to explicitly specify it:
    myobj.GetVar<int>(0);

    And I'm not mistaken, I believe that dwks's "solution" is what object factories were invented for. Perhaps a quick read on those might enlighten a little.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #11
    The larch
    Join Date
    May 2006
    Posts
    3,573
    In short, the VarList::GetVar method should be implemented and called like this:

    Code:
    //no need for specializations
    template<typename valtype>
    valtype VarList::GetVar(size_t index)
    {
        return boost::any_cast<valtype>(variables.at(index));
    };
    
    //when called the template type does not appear as one of the arguments
    //hence it needs to specified explicitly
        std::cout << "Var[0] = " << test.GetVar<int>(0) << std::endl;
        std::cout << "Var[1] = " << test.GetVar<std::string>(1) << std::endl;
    It also appears to me that there isn't much reason to allocate the boost::any objects with new, so you might use regular objects with std::vector.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  12. #12
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,893
    You want a boost::variant, not a boost::any. Variant is a so-called "discriminated union". It's an object that can have one of a fixed set of types, specified at compile time, but can change between these types at runtime. E.g.
    Code:
    typedef boost::variant<std::string, int, double, FunctionRef> ScriptVarType;
    
    ScriptVarType v1 = "Hello, World!";
    v1 = 24.5;
    v1 = GetFunctionRef("foo");
    Then there's boost::get and boost::apply_visitor to do something with those variables. Where you use which depends on the context. Read the documentation for more information.

    Variant vs. Any:
    Variant is faster. You can use variant's facilities to write simpler code for situations where it's viable to treat all contained types the same.
    Any can hold any type, not just a compile-time-specified set. It's messier to work with and doesn't support type-safe dispatch.

    The rule is: use variant whenever it can satisfy your needs. Use any only when you really need any type (e.g. holding user-supplied data inside your library).
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Default class template problem
    By Elysia in forum C++ Programming
    Replies: 5
    Last Post: 07-11-2008, 08:44 AM
  2. Code review
    By Elysia in forum C++ Programming
    Replies: 71
    Last Post: 05-13-2008, 09:42 PM
  3. another template question
    By l2u in forum C++ Programming
    Replies: 4
    Last Post: 02-13-2008, 02:52 PM
  4. Quick question about class template
    By merixa in forum C++ Programming
    Replies: 5
    Last Post: 12-06-2005, 10:43 PM
  5. Nested loop frustration
    By caroundw5h in forum C Programming
    Replies: 14
    Last Post: 03-15-2004, 08:45 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21