Thread: template programming:how to prevent someone passing classes to my function template

  1. #1
    Registered User
    Join Date
    Jan 2011
    Posts
    222

    template programming:how to prevent someone passing classes to my function template

    hi,


    let say i have a following scenario:

    a function like tis
    Code:
    
    template <typename T1>
    print (T1 x){
      cout << x << "\n";
    }
    how do i prevent user passing a class or a structure or aanoter function to my function print. I mean i know if a wrong thing is passed that i'll get an error eveuntaly but is there a way to explicitly check what has been passed. How is this done usually ?

    thnx

    baxy

  2. #2
    Programming Wraith GReaper's Avatar
    Join Date
    Apr 2009
    Location
    Greece
    Posts
    2,738
    Why not let it to the implementer of the other class to provide the stream I/O operators?
    Devoted my life to programming...

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I cannot say that I have ever used it myself, but check out the Boost Concept Check library. Apparently it was slated for inclusion into C++11, but was eventually abandoned or postponed.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by GReaper View Post
    Why not let it to the implementer of the other class to provide the stream I/O operators?
    They have to do that already, with this approach. Wrapping the operation in a function makes it possible to change the implementation later (possibly to one that doesn't use ostream formatted output). As far as OP's question, I challenge the original requirement -- why shouldn't we be able to pass any object we want to print(), as long as a stream insertion operator is implemented?

    The error messages generated can be hard to read, but there are techniques for making them somewhat easier to understand. laserlight mentioned this in post #3
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  5. #5
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    For education and for fun, you can do it this way (using C++11):

    Code:
    #include <type_traits>
    #include <vector>
    
    template<typename T>
    auto foo(const T& printy) -> void
    {
    	static_assert(!std::is_class<T>::value, "Type of argument printy must not be a class.");
    	bar(printy);
    }
    
    template<typename T>
    auto bar(const T& printy) -> void
    {
    	std::cout << printy << std::endl;
    }
    
    int main()
    {
    	int x = 0;
    	std::vector<int> v;
    	foo(x); // Change to v and you get a compile error
    	return 0;
    }
    The reason I split foo into foo and bar is to prevent further compile errors from the compiler. You can put them together if you want.
    Of course, this prevents you from passing in an object that supports operator <<. So if you conditionally want to detect if it supports being printed to an ostream (such as cout) with the << operator, you can do this (hang on to your boots!):

    Code:
    #include <type_traits>
    #include <vector>
    #include <utility>
    
    template<typename T>
    struct SupportsLeftStreamOperator
    {
    	typedef char yes[1];
    	typedef char no[2];
    
    	template<typename U> static yes& check(decltype(std::cout << std::declval<U>())*);
    	template<typename U> static no& check(...);
    
    	static const bool value = (sizeof(check<T>(nullptr)) == sizeof(yes));
    };
    
    template<typename T>
    auto foo(const T& printy) -> void
    {
    	static_assert(!std::is_class<T>::value || SupportsLeftStreamOperator<T>::value, "Type of argument must support operator <<.");
    	bar(printy);
    }
    
    template<typename T>
    auto bar(const T& printy) -> void
    {
    	std::cout << printy << std::endl;
    }
    
    class test {};
    
    std::ostream& operator << (std::ostream& out, const test& right) { return out; }
    
    int main()
    {
    	int x = 0;
    	test t;
    	std::vector<int> v;
    	foo(x);
    	foo(t);
    	//foo(v); // This will cause a compile error
    	return 0;
    }
    So how the heck does this work, you wonder? What kind of insane magic is this? Well, first of, read up on SFINAE. That's what this builds upon.
    The idea is that SupportsLeftStreamOperator calls check which is a template function. It will take one argument - a pointer to the type of the expression you get when sending the object to std::cout (ie std::cout << myobj). If this isn't possible, ie the type does not an appropriate overload, the compiler will skip the function and take the next function which is a catch-all. The "..." argument list makes it possible to catch all types of types without fuss and ambiguity. Then I simply compare the size of the type the function call would have yielded, had it been called. sizeof does not actually call functions, so I'm okay here. I'm returning a reference to an array because that's allowed according to the standard, while returning a simple array is not. Check the documentation for std::declval, too.
    This is tricky stuff and can take some time getting used to. Don't use it in production code. At least not until you can reproduce it and understand the implications and compiler limitations.
    But if you just want to play around? Sure - go right ahead!
    Last edited by Elysia; 09-13-2013 at 03:23 PM. Reason: Forgot header for std::declval
    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.

  6. #6
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by baxy View Post
    How is this done usually?
    It isn't. In the real world we don't arbitrarily stop people from doing things that would be perfectly fine, for no reason.
    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"

  7. #7
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by baxy View Post
    how do i prevent user passing a class or a structure or aanoter function to my function print.
    You want to prevent a user passing a class, struct, or a function? What is the user permitted to pass? If you're that restrictive in what you want to pass, why is the function a template in the first place?

    Usually, if the number of types permitted is small, the solution is to not do it as a template, but to overload the function for the specified types.

    In C++11 there is the <type_traits> header, which can be used to check (at compile time) particular attributes of types.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 3
    Last Post: 01-30-2011, 04:28 PM
  2. Specialising a member function with a template template parameter
    By the4thamigo_uk in forum C++ Programming
    Replies: 10
    Last Post: 10-12-2007, 04:37 AM
  3. Passing a set to a template function
    By cloudy in forum C++ Programming
    Replies: 1
    Last Post: 10-09-2007, 06:57 AM
  4. passing unspecialised template classes as function arguments
    By reanimated in forum C++ Programming
    Replies: 1
    Last Post: 02-23-2006, 11:50 AM
  5. Passing Template values on to other classes
    By vinsta18 in forum C++ Programming
    Replies: 5
    Last Post: 10-20-2004, 05:26 PM