Thread: A Question About C++ Template

  1. #1
    C/C++Newbie Antigloss's Avatar
    Join Date
    May 2005
    Posts
    216

    A Question About C++ Template

    Greetings.

    I wanna write a template function that accepts any container type (such as vector, set, list) but restricts the element type of the container to be string.

    I've tried this, but failed.

    Code:
    #include <iostream>
    #include <vector>
    #include <string>
    
    using namespace std;
    
    template <typename C>
    void t(C <string>* args)
    {
    }
    
    int main()
    {
    	vector<string> vi;
    	t(&vi);	
    	return 0;
    }
    error: C is not a template
    void t(C <string>* args)


    Please kindly help. Thank you.

  2. #2
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,616
    Since you have not really demonstrated why you need a template template parameter, I would suggest overloading instead:

    Code:
    void t(vector<string>& args);
    void t(list<string>& args);
    :
    :
    You may be chasing a rainbow... STL containers often have different member functions. A vector isn't accessed the same as a list or a stack for instance.

  3. #3
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I don't see why you would want to accept any type of container since they have different interfaces. But regardless, to satisfy your curiosity, it's not easy to do in the current standard because there's just no explicit tool that does this. Soon(ish), we'll be getting concepts, but until the standard library gets concepts, it's not going to help that much except for user-defined types. But concepts would allow you to do what you want to do.

    To do it in the current standard, you can try to probe the container to get its type, e.g.:

    Code:
    template<typename T>
    void foo(T& cont)
    {
        using Element_t = std::decay_t<decltype(*cont.begin())>;
        static_assert(std::is_same_v<Element_t, string>, "Container must have string elements.");
        // ...
    }
    As you can see, this involves a fair bit of template "magic". I haven't tested compiling this, but the idea is to get the "type" of the element at the first position in the container, the strip any references, etc, then compare that to, say, a string, and if that checks fails, display an error.
    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.

  4. #4
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,616
    That's way too fancy for such a simple assert:

    Code:
    #include <type_traits>
    #include <vector>
    #include <string>
    using namespace std;
     
    template <typename T>
    void foo(T& cont)
    {
    	static_assert(is_same<typename T::value_type, string>::value, "Contained element must be string");
    }
     
    int main() {
    	vector<int> vi;
    	foo(vi);
    	return 0;
    }

  5. #5
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    I actually liked the use of std::decay though. I'm confident it means that you can then template your function with std::string&, std::string&&, std::string const& and it'll work fine. Unless the value_type of std::vector<std::string const&> evaluates to std::string but I'm not sure that it does.

  6. #6
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,616
    Can you even have a container with a reference type, though? I thought not and it fails when I try it.

  7. #7
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Hey, you're right, they can't! You know what's funny, I've actually never tried. Okay, I guess the std::decay call is unnecessary then.

  8. #8
    [](){}(); manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    *nullptr
    Posts
    2,657
    Here is a solution without using static_assert or specializations :

    Code:
    #include <vector>
    #include <deque>
    #include <list>
    #include <string>
    #include <iostream>
    
    
    template <template <typename, typename ...> class Container, typename ...Extra>
    size_t foo(Container<std::string, Extra...> C) {
      return C.size();
    }
    
    
    int main() {
      std::string a, b;
    
    
      std::cout << foo(std::vector<std::string>{a,b}) << std::endl; // works
      std::cout << foo(std::deque<std::string>{a,b}) << std::endl;  // works
      std::cout << foo(std::list<std::string>{a,b}) << std::endl;   // works
    
    
      // std::cout << foo(std::deque<std::string>{1,2}) << std::endl; // Doesn't work
    
    
    }

  9. #9
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    You will also get horrible error messages if it fails.
    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.

  10. #10
    [](){}(); manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    *nullptr
    Posts
    2,657
    Quote Originally Posted by Elysia View Post
    You will also get horrible error messages if it fails.
    True.
    I guess that has stopped bothering me when writing C++!
    In this case, there is a lot of horrible messages and a single reasonable one.
    Code:
        ...
        note: candidate constructor not viable: no known conversion from 'int' to      'const value_type' (aka 'const std::__1::basic_string<char>') for 2nd argument
        deque(size_type __n, const value_type& __v);
        ...

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    That's still a horrible message. That's why you should use static_asserts. Try explaining that to newbies.
    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.

  12. #12
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    I think that's a good point. At first, I was also opposed to a static assert and kind of was thinking about how manasij did it, where you pass the template type as a templated parameter. But I agree, the expressiveness granted by a static_assert far outweighs any other approach. C++ template error messages are the stuff of legends for good reason lol XD

  13. #13
    Registered User
    Join Date
    Nov 2012
    Posts
    1,393
    Quote Originally Posted by Antigloss View Post
    I wanna write a template function that accepts any container type (such as vector, set, list) but restricts the element type of the container to be string.
    You may achieve this result if you include some code in your method that will only compile with a string type. The code doesn't even need to actually run. Just threatening to run some string-specific code is enough.

    Code:
    using namespace std;
    
    template<class CONT>
    void f(CONT* obj) {
        // Trick compiler into requiring that T of CONT<T> is a string.
        if (0) {
            (void)obj->at(0).substr((string::size_type)0,string::npos);
        }
    
        // ...
    }
    If you try to call f with something whose elements do not respond to substr(size_type,size_type), you should get a diagnostic leading back to the offending code. substr is just an example, of course.

    Code:
    struct my_string : string {
        my_string() = default;
        my_string(string s) : string(s) {}
        my_string(const char *s) : string(s) {}
    };
    
    int main()
    {
        vector<string> vs {"one", "two", "three"};
        f(&vs); // OK
    
        vector<my_string> vm {"one","two","three"};
        f(&vm); // OK
    
        vector<double> vd {1,2,3};
        f(&vd); // COMPILER ERROR
    }

  14. #14
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Out of curiosity, what's this function going to actually be doing? I'm hard-pressed to think of a scenario where you can pass in any container just so long as its value_type is string.

  15. #15
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by c99tutorial View Post
    You may achieve this result if you include some code in your method that will only compile with a string type. The code doesn't even need to actually run. Just threatening to run some string-specific code is enough.
    Again this will cause horrible compile errors, warning of unused code and it looks horrible to anyone who looks at it.
    Just make a check and deny erroneous types. That way, it's clear what the code is trying to do.
    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. Template question
    By stefanyco in forum C++ Programming
    Replies: 6
    Last Post: 10-18-2011, 02:21 PM
  2. Another template question...
    By darren78 in forum C++ Programming
    Replies: 6
    Last Post: 08-13-2010, 09:20 AM
  3. template question
    By wxjeacen in forum C++ Programming
    Replies: 6
    Last Post: 02-25-2009, 02:18 AM
  4. another template question
    By l2u in forum C++ Programming
    Replies: 4
    Last Post: 02-13-2008, 03:52 PM
  5. Another template question
    By grscot in forum C++ Programming
    Replies: 2
    Last Post: 04-28-2003, 06:16 PM

Tags for this Thread