Thread: Passing multiple variables using function

  1. #1
    Registered User
    Join Date
    Dec 2008
    Location
    California
    Posts
    37

    Passing multiple variables using function

    I'm creating a function right now but I want to pass all the text I want to render in one function call. Is it possible? Just like what the stringstream do.

    Let's say I want to pass:

    Code:
    stringstream text;
    text << "Frame: " << fps << " X: " << x<< " Y: " << y;
    
    renderText(text, 10, 10, 10); // void renderText( what should I put here?, int x, int y, int fsize);
    is there any other way around?

  2. #2
    The larch
    Join Date
    May 2006
    Posts
    3,573
    You can make a class that overloads operator<<. (Remove const-ness if rendering modifies the state of TextRenderer, make friends as needed etc.)

    Code:
    #include <iostream>
    
    class TextRenderer
    {
    };
    
    template <class T>
    const TextRenderer& operator<< (const TextRenderer& renderer, const T& value)
    {
        std::cout << value;
        return renderer;
    }
    
    int main()
    {
        TextRenderer output;
        output << "X is " << 10 << ", Y is " << 20 << '\n';
    }
    Another way might be to create a function that accepts a string and build the string with stringstream (this doesn't look very nice):

    Code:
    #include <iostream>
    #include <sstream>
    #include <string>
    void render_text(const std::string& msg)
    {
        std::cout << msg;
    }
    
    int main()
    {
        std::stringstream ss;
        render_text(static_cast<std::stringstream&>(ss << "X is " << 10 << ", Y is " << 20 << '\n').str());
    }
    Yet another way might be to get boost and use boost::format to build the string.

    Code:
    #include <iostream>
    #include <string>
    #include <boost/format.hpp>
    
    void render_text(const std::string& msg)
    {
        std::cout << msg;
    }
    
    int main()
    {
        render_text(boost::str((boost::format("X is %d, Y is %d\n") % 10 % 20)));
    }
    In any case, without variadic templates (C++0x feature) there is no good way to create a function that accepts an arbitrary number of arguments with arbitrary types.
    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).

  3. #3
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    O_o

    Do you mean you want to combine all of that source into one line?

    Code:
    renderText((stringstream() << "Frame: " << fps << " X: " << x<< " Y: " << y), 10, 10, 10);
    Do you mean you just want to pass the 'std::stringstream' instance after you've constructed the string? (As you've done in the post.)

    Do you mean you just want to pass the string you've constructed without using 'std::stringstream' in the signature?

    Code:
    renderText(text.str(), 10, 10, 10);
    Why not accept a constant reference to a 'std::string' and provide overloads to do the other bits?

    Code:
    void renderText(const std::string &, int x, int y, int fsize);
    Soma

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    You could do something like this...
    Code:
    #include <vector>
    #include <string>
    #include <assert.h>
    #include <iostream>
    
    template<typename T> class MltArgs
    {
    public:
    	//MltArgs() { }
    
    	//MltArgs(T Val)
    	//{
    	//	m_Args.push_back(Val);
    	//}
    
    	MltArgs& operator << (T Val)
    	{
    		m_Args.push_back(Val);
    		return *this;
    	}
    
    	//MltArgs& operator << (const MltArgs& Val)
    	//{
    	//	for (std::size_t i = Val.NumOfArgs(); i++)
    	//		m_Args.push_back(Val[i]);
    	//	return *this;
    	//}
    
    	std::size_t NumOfArgs()
    	{
    		return m_Args.size();
    	}
    
    	T& operator [] (std::size_t i)
    	{
    		assert(i < m_Args.size());
    		return m_Args[i];
    	}
    
    private:
    	std::vector<T> m_Args;
    };
    
    void foo(MltArgs<std::string>& Args)
    {
    	std::cout << "The following arguments were passed:\n";
    	for (std::size_t i = 0; i < Args.NumOfArgs(); i++)
    		std::cout << Args[i] << std::endl;
    }
    
    int main()
    {
    	std::string World = "world!";
    	foo( (MltArgs<std::string>() << "Hello" << "there" << World) );
    }
    The only problem is the lot of copying, but otherwise extra trickiness is required to make implicit conversions work. I'm open to suggestions on that one.
    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.

  5. #5
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    O_o

    If you are going to go that root, spawning a class for indirection, you may as well employee templates, overload 'operator ,' and cache a reference whenever possible. At least then you don't have to lose type information.

    Soma

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    You are better at this than me...
    You are allowed to type an example
    This was just a short implementation written from scratch that "worked", although not really well.
    Last edited by Elysia; 01-24-2009 at 03:10 PM.
    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.

  7. #7
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    I don't like posting examples that depend on my own stuff. (I may when I get it all fixed.)

    I don't like posting examples that depend on Boost. (I don't even use it anymore.)

    You need a lot of meta-programming primitives to do this correctly. (I don't want to code them all before posting.)

    I will simply avoid the issues. (This will not work if constant character strings are used directly for example.)

    This is the most basic form of what I was suggesting. It uses 'operator ,' as a means of concatenating pairs to generate a modified type list that always stores a constant reference.

    Soma

    Code:
    #include <iostream>
    #include <string>
    
    struct empty_type{};
    
    template
    <
       typename node_F = empty_type,
       typename list_F = empty_type
    >
    struct reference_list
    {
       typedef reference_list<node_F, list_F> type;
       reference_list
       (
          const node_F & n_f,
          const list_F & l_f
       ):
          n_m(n_f),
          l_m(l_f)
       {
       }
       template
       <
          typename type_FR
       >
       typename reference_list<type_FR, typename reference_list<node_F, list_F>::type>::type operator ,
       (
          const type_FR & f
       )
       {
          return(typename reference_list<type_FR, typename reference_list<node_F, list_F>::type>::type(f, *this));
       }
       const node_F & n_m;
       const list_F & l_m;
    };
    
    template
    <
       typename node_F
    >
    struct reference_list<node_F, empty_type>
    {
       typedef reference_list<node_F, empty_type> type;
       reference_list
       (
          const node_F & n_f
       ):
          n_m(n_f)
       {
       }
       template
       <
          typename type_FR
       >
       typename reference_list<type_FR, typename reference_list<node_F, empty_type>::type>::type operator ,
       (
          const type_FR & f
       )
       {
          return(typename reference_list<type_FR, typename reference_list<node_F, empty_type>::type>::type(f, *this));
       }
       const node_F & n_m;
    };
    
    template <> struct reference_list<empty_type, empty_type>
    {
       typedef reference_list<empty_type, empty_type> type;
       reference_list()
       {
       }
       template
       <
          typename type_FR
       >
       typename reference_list<type_FR, empty_type>::type operator ,
       (
          const type_FR & f
       )
       {
          return(typename reference_list<type_FR, empty_type>::type(f));
       }
    };
    
    template
    <
       typename node_F
    >
    void do_something
    (
       const reference_list<node_F, empty_type> & f,
       int x_f,
       int y_f,
       int size_f
    )
    {
       std::cout << "Data:(" << f.n_m << ") X:(" << x_f << ") Y:(" << y_f << ") Size:(" << size_f << ")\n";
    }
    
    template
    <
       typename node_F,
       typename list_F
    >
    void do_something
    (
       const reference_list<node_F, list_F> & f,
       int x_f,
       int y_f,
       int size_f
    )
    {
       do_something(f.l_m, x_f, y_f, size_f);
       std::cout << "Data:(" << f.n_m << ") X:(" << x_f << ") Y:(" << y_f << ") Size:(" << size_f << ")\n";
    }
    
    typedef reference_list<> arguments_list;
    arguments_list join;
    
    int main()
    {
       do_something((join, std::string("Hello"), ',', ' ' , std::string("World"), '!', 1, 2.0, 3.0f), 10, 10, 10);
       return(0);
    }

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Another big, tricky example from you! Yes!
    It's a shame you won't post complete examples, but I can understand your reluctance. Not about boost, though. Terrific, that. Boost.
    The only thing that I know I might punch a hole in is that it concatenates the arguments instead of preserving them... not good for passing multiple arguments to a function. It kind of reinvents the wheel with stringstreams, but using "," instead of "<<", no?

    I'd really big interested in a more generic solution for passing multiple arguments until compilers start supporting the new C++0x solution.
    Not that such a solution would be required in this particular scenario, but meh, whatever. It's cool!
    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.

  9. #9
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by Elysia View Post
    You are better than this at me...
    Perhaps your ego prevented you fingers from saying what you meant there .
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It simply meant that phantomotap is a wizard with far more experience with template programming to pull off advanced stunts like this
    Last edited by Elysia; 01-24-2009 at 03:12 PM.
    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
    Kiss the monkey. CodeMonkey's Avatar
    Join Date
    Sep 2001
    Posts
    937
    Could you create a stream buffer that does the work of the function for every flush?
    "If you tell the truth, you don't have to remember anything"
    -Mark Twain

  12. #12
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    The only thing that I know I might punch a hole in is that it concatenates the arguments instead of preserving them... not good for passing multiple arguments to a function.
    It does concatenate the arguments. It preserves the actual arguments and the type of arguments. (The lack of support for constant character strings is the problem.)

    It kind of reinvents the wheel with stringstreams, but using "," instead of "<<", no?
    This doesn't serialize the values associated with the types. This is on the other side of the universe. I've created a kind of variadic template using a specific purpose type list. I've then pealed off the type information with recursion--exactly as you will for C++0x variadic templates.

    I've altered the example. I suggest you compile and run the example. You can see the untouched type information for yourself.

    Actually, not really.
    ^_^

    There is a tremendous difference between "You are better at this than me..." and "You are better than this at me...".

    Soma

    Code:
    #include <iostream>
    #include <string>
    
    struct empty_type{};
    
    template
    <
       typename node_F = empty_type,
       typename list_F = empty_type
    >
    struct reference_list
    {
       typedef reference_list<node_F, list_F> type;
       reference_list
       (
          const node_F & n_f,
          const list_F & l_f
       ):
          n_m(n_f),
          l_m(l_f)
       {
       }
       template
       <
          typename type_FR
       >
       typename reference_list<type_FR, typename reference_list<node_F, list_F>::type>::type operator ,
       (
          const type_FR & f
       )
       {
          return(typename reference_list<type_FR, typename reference_list<node_F, list_F>::type>::type(f, *this));
       }
       const node_F & n_m;
       const list_F & l_m;
    };
    
    template
    <
       typename node_F
    >
    struct reference_list<node_F, empty_type>
    {
       typedef reference_list<node_F, empty_type> type;
       reference_list
       (
          const node_F & n_f
       ):
          n_m(n_f)
       {
       }
       template
       <
          typename type_FR
       >
       typename reference_list<type_FR, typename reference_list<node_F, empty_type>::type>::type operator ,
       (
          const type_FR & f
       )
       {
          return(typename reference_list<type_FR, typename reference_list<node_F, empty_type>::type>::type(f, *this));
       }
       const node_F & n_m;
    };
    
    template <> struct reference_list<empty_type, empty_type>
    {
       typedef reference_list<empty_type, empty_type> type;
       reference_list()
       {
       }
       template
       <
          typename type_FR
       >
       typename reference_list<type_FR, empty_type>::type operator ,
       (
          const type_FR & f
       )
       {
          return(typename reference_list<type_FR, empty_type>::type(f));
       }
    };
    
    void do_something
    (
       const std::string & f,
       int x_f,
       int y_f,
       int size_f
    )
    {
       std::cout << "std::string:(" << f << ") X:(" << x_f << ") Y:(" << y_f << ") Size:(" << size_f << ")\n";
    }
    
    void do_something
    (
       const int & f,
       int x_f,
       int y_f,
       int size_f
    )
    {
       std::cout << "int:(" << f << ") X:(" << x_f << ") Y:(" << y_f << ") Size:(" << size_f << ")\n";
    }
    
    void do_something
    (
       const double & f,
       int x_f,
       int y_f,
       int size_f
    )
    {
       std::cout << "double:(" << f << ") X:(" << x_f << ") Y:(" << y_f << ") Size:(" << size_f << ")\n";
    }
    
    void do_something
    (
       const float & f,
       int x_f,
       int y_f,
       int size_f
    )
    {
       std::cout << "float:(" << f << ") X:(" << x_f << ") Y:(" << y_f << ") Size:(" << size_f << ")\n";
    }
    
    template
    <
       typename node_F
    >
    void do_something
    (
       const node_F & f,
       int x_f,
       int y_f,
       int size_f
    )
    {
       std::cout << "Data:(" << f << ") X:(" << x_f << ") Y:(" << y_f << ") Size:(" << size_f << ")\n";
    }
    
    template
    <
       typename node_F
    >
    void do_something
    (
       const reference_list<node_F, empty_type> & f,
       int x_f,
       int y_f,
       int size_f
    )
    {
       do_something(f.n_m, x_f, y_f, size_f);
    }
    
    template
    <
       typename node_F,
       typename list_F
    >
    void do_something
    (
       const reference_list<node_F, list_F> & f,
       int x_f,
       int y_f,
       int size_f
    )
    {
       do_something(f.l_m, x_f, y_f, size_f);
       do_something(f.n_m, x_f, y_f, size_f);
    }
    
    typedef reference_list<> arguments_list;
    arguments_list join;
    
    int main()
    {
       do_something((join, std::string("Hello"), ',', ' ' , std::string("World"), '!', 1, 2.0, 3.0f), 10, 10, 10);
       return(0);
    }

  13. #13
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by phantomotap View Post
    ^_^

    There is a tremendous difference between "You are better at this than me..." and "You are better than this at me...".
    o_O
    I didn't realize I had mixed up the order of the words... I didn't think of it.
    Hehe. Oops, yes, your order is the correct one ^_^
    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.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. doubt in c parser coding
    By akshara.sinha in forum C Programming
    Replies: 4
    Last Post: 12-23-2007, 01:49 PM
  2. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  3. Passing variables to system() function?
    By carter192 in forum C Programming
    Replies: 5
    Last Post: 12-19-2006, 09:44 PM
  4. Bisection Method function value at root incorrect
    By mr_glass in forum C Programming
    Replies: 3
    Last Post: 11-10-2005, 09:10 AM
  5. passing variables by reference
    By neandrake in forum C++ Programming
    Replies: 2
    Last Post: 06-04-2003, 07:59 AM