[RESOLVED] template function in non-template class
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 8 of 8

Thread: [RESOLVED] template function in non-template class

  1. #1
    Join Date
    Jul 2017
    Posts
    12

    [RESOLVED] template function in non-template class

    I am trying to implement BigInteger library by myself. I am storing numbers in std::string.
    The header file (BigInt.h) contains:
    Code:
    #ifndef BIGINT_H
    #define BIGINT_H
    
    #include <iostream>
    //#include <vector>
    
    /**Specifications:
    *   Constructor: can take, int, string(formatted as number), float or double
    *   operators to define +, -, *, /, %, power(), <<, >>
    */
    
    class BigInt
    {
    public:
        /** Default constructor */
        BigInt();
    
    
        /** string constructor */
        BigInt(const std::string&);
    
    
        /** int, float or double constructor */
        template<typename T>
        BigInt(const T&);
    
        /** Default destructor */
        virtual ~BigInt();
    
        /** Copy constructor
         *  \param other Object to copy from
         */
        BigInt(const BigInt& other);
    
        /** Assignment operator
         *  \param other Object to assign from
         *  \return A reference to this
         */
        BigInt& operator=(const BigInt& other);
    
        /**
        *   Overloaded << ostream operator
        */
        friend std::ostream& operator<<(std::ostream& os, const BigInt& bigInt);
    
    protected:
    
    private:
        /**
        *   Number is represented as:
        *   +0.123324 or -0.1232432
        *   +123 or -123 etc
        *   [+ or -] then [numbers] then maybe [.] then [more numbers]
        */
        std::string dec_rep;
    };
    
    #endif // BIGINT_H
    definition of member functions is in BigInt.cpp:
    Code:
    #include "BigInt.h"
    
    #include <string>
    #include <regex>
    //#include <sstream>
    
    BigInt::BigInt()
    {
        //ctor
        dec_rep = "+0";
    }
    
    template<typename T>
    BigInt::BigInt(const T& n)
    {
        dec_rep = std::to_string(n);
        if( dec_rep[0] != '+' && dec_rep[0]!='-')
        {
            dec_rep = "+" + dec_rep;
        }
    }
    
    
    /**
    * it accepts input as string if it is correctly formatted as number
    * accepted forms are: 1234, 1.234, +1233, +1.234, 0.234, .234, +.234, -123 etc
    * these are unaccepted; --123, +-23, -+32, 0.234.0 or any other wrong format
    */
    BigInt::BigInt(const std::string& str)
    {
        std::regex re("[-+]?([0-9]*\\.[0-9]+)"); //regular expression to check if input is in proper format
        std::smatch m;
        if(std::regex_match(str, m, re))
        {
            dec_rep = str;
            if((str[0] == '+' || str[0] == '-') && str[1] == '.')
            {
                dec_rep = dec_rep[0] + "0" + dec_rep.substr(1);
            }
            else if(str[0] == '.')
            {
                dec_rep = "+0" + dec_rep;
            }
            else if(str[0]>='0' && str[0]<='9')
            {
                dec_rep = "+" + dec_rep;
            }
        }
    }
    
    BigInt::~BigInt()
    {
        //dtor
    }
    
    BigInt::BigInt(const BigInt& other)
    {
        //copy ctor
    }
    
    BigInt& BigInt::operator=(const BigInt& rhs)
    {
        if (this == &rhs) return *this; // handle self assignment
        //assignment operator
        return *this;
    }
    
    std::ostream& operator<<(std::ostream& os, const BigInt& bigInt)
    {
        os<<bigInt.dec_rep;
        return os;
    }

    main() is in main.cpp:
    Code:
    #include <iostream>
    
    #include "BigInt.h"
    
    using namespace std;
    
    int main()
    {
        BigInt n(1);  //Line 9 where 1st error comes
        BigInt n_default;
        BigInt str_n("1"); //Line 11 where 2nd error comes
        cout<<n<<" "<<n_default<<" "<<str_n<<endl;
        cout << "Hello world!" << endl;
        return 0;
    }
    When I try to run it, it shows following errors:
    obj/Debug/main.o||In function `main':|
    1. undefined reference to `BigInt::BigInt<int>(int const&)' on line 9 of main.cpp
    2. undefined reference to `BigInt::BigInt<char [2]>(char const (&) [2])' on line 11 of main.cpp
    3. error: ld returned 1 exit status
    ||=== Build failed: 3 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

    I'm using code-blocks 16.01 with GCC compiler on Linux Mint 18.2 'Sonya' (64 bit).
    Attached Files Attached Files

  2. #2
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    5,700

    Re: template function in non-template class

    When templates are used, you can't separate header from implementation. The implementation has to placed in the header - similar to how the STL classes are implemented.
    All advice is offered in good faith only. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/

    C++17 Compiler: Microsoft VS2017 (15.3.4)

  3. #3
    Join Date
    Jul 2017
    Posts
    12

    Re: template function in non-template class

    Quote Originally Posted by 2kaud View Post
    When templates are used, you can't separate header from implementation. The implementation has to placed in the header - similar to how the STL classes are implemented.
    I moved all code in one file: BigInt.h

    But now it gives different errors. It wants to use template function when string argument is passed. But I have already overloaded the function with separate string argument, so why doesn't it use that?

    Errors:
    1. no matching function for call to ‘to_string(const char [2])’
    2. invalid conversion from ‘const char*’ to ‘int’ [-fpermissive]
    and other errors similar to error 2

    Updated file is uploaded.
    Attached Files Attached Files

  4. #4
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    5,700

    Re: template function in non-template class

    It wants to use template function when string argument is passed. But I have already overloaded the function with separate string argument, so why doesn't it use that?
    The template function will match any constructor call. Hence it has matched the template with type char[2]. What you need to do is to have an explicit template specialisation(s) for when you don't want the normal template to apply. Consider

    Code:
    template<>
    BigInt::BigInt(const std::string& str)
    {
    ...
    }
    Note that this will also apply to the copy constructor.
    Last edited by 2kaud; July 17th, 2017 at 01:32 PM.
    All advice is offered in good faith only. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/

    C++17 Compiler: Microsoft VS2017 (15.3.4)

  5. #5
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,724

    Re: template function in non-template class

    Quote Originally Posted by JohnnyTest
    But now it gives different errors. It wants to use template function when string argument is passed. But I have already overloaded the function with separate string argument, so why doesn't it use that?
    Recall that there is the concept of a null terminated string as inherited from C (i.e., contiguous sequences of char, stored in arrays, terminated by a null character), and then there are string objects with the type of std::string. It looks like the compiler chose the template because the type of the argument was that of a char array rather than a std::string. There may be other solutions, but perhaps one quick solution would be to overload for const char*. This overload can delegate to the constructor that overloads for std::string const reference, e.g., by explicitly constructing a std::string object as the argument as it delegates, so you don't really do extra work.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  6. #6
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    5,700

    Re: template function in non-template class

    Code:
    BigInt str_n("1"); //Line 11 where 2nd error comes
    This is calling the constructor with type const char* and matches the standard template. If you instead use

    Code:
    BigInt str_n("1"s); //Line 11 where 2nd error comes
    then this explicitly makes the parameter of type string which then matches the explicit template specialisation for string. As laserlight suggested in post #5, you might also want to provide a function overload for type const char* (it can't be a template specialisation as the type has to be a ref because the main template uses a ref).

    Note that if you use the s string suffix, then you either need to use using name std at the beginning of the program or

    Code:
    using namespace std::string_literals;
    before the string suffix is used. See https://msdn.microsoft.com/en-us/library/69ze775t.aspx

    The code below compiles
    Code:
    #include <iostream>
    #include <string>
    #include <regex>
    //#include <vector>
    
    /**Specifications:
    *   Constructor: can take, int, string(formatted as number), float or double
    *   operators to define +, -, *, /, %, power(), <<, >>
    */
    
    class BigInt
    {
    public:
    	/** Default constructor */
    	BigInt();
    
    	/** int, float or double constructor */
    	template<typename T>
    	BigInt(const T&);
    
    	/** string constructor */
    	template<>
    	BigInt(const std::string&);
    
            /** char * constructor */
    	BigInt(const char * const);
    
    
    	/** Default destructor */
    	virtual ~BigInt();
    
    	/** Copy constructor
    	*  \param other Object to copy from
    	*/
    	BigInt(const BigInt& other);
    
    	/** Assignment operator
    	*  \param other Object to assign from
    	*  \return A reference to this
    	*/
    	BigInt& operator=(const BigInt& other);
    
    	/**
    	*   Overloaded << ostream operator
    	*/
    	friend std::ostream& operator<<(std::ostream& os, const BigInt& bigInt);
    
    protected:
    
    private:
    	/**
    	*   Number is represented as:
    	*   +0.123324 or -0.1232432
    	*   +123 or -123 etc
    	*   [+ or -] then [numbers] then maybe [.] then [more numbers]
    	*/
    	std::string dec_rep;
    };
    
    BigInt::BigInt()
    {
    	//ctor
    	dec_rep = "+0";
    }
    
    template<typename T>
    BigInt::BigInt(const T& n)
    {
    	dec_rep = std::to_string(n);
    	if (dec_rep[0] != '+' && dec_rep[0] != '-')
    	{
    		dec_rep = "+" + dec_rep;
    	}
    }
    
    template<>
    BigInt::BigInt(const std::string& str)
    {
    	std::regex re("[-+]?([0-9]*\\.[0-9]+)");
    	std::smatch m;
    	if (std::regex_match(str, m, re))
    	{
    		dec_rep = str;
    		if ((str[0] == '+' || str[0] == '-') && str[1] == '.')
    		{
    			dec_rep = dec_rep[0] + "0" + dec_rep.substr(1);
    		}
    		else if (str[0] == '.')
    		{
    			dec_rep = "+0" + dec_rep;
    		}
    		else if (str[0] >= '0' && str[0] <= '9')
    		{
    			dec_rep = "+" + dec_rep;
    		}
    	}
    }
    
    BigInt::BigInt(const char * const cst) : BigInt(std::string(cst)) {}
    
    BigInt::~BigInt()
    {
    	//dtor
    }
    
    BigInt::BigInt(const BigInt& other)
    {
    	//copy ctor
    }
    
    BigInt& BigInt::operator=(const BigInt& rhs)
    {
    	if (this == &rhs) return *this; // handle self assignment
    									//assignment operator
    	return *this;
    }
    
    std::ostream& operator<<(std::ostream& os, const BigInt& bigInt)
    {
    	os << bigInt.dec_rep;
    	return os;
    }
    
    int main()
    {
    	using namespace std::string_literals;
    
    	BigInt n(1);  //Line 9 where 1st error comes
    	BigInt n_default;
    	BigInt str_n("1"s); //Line 11 where 2nd error comes
    	std::cout << n << " " << n_default << " " << str_n << std::endl;
    	std::cout << "Hello world!" << std::endl;
    	return 0;
    }
    Last edited by 2kaud; July 17th, 2017 at 01:36 PM. Reason: Added constr for char *
    All advice is offered in good faith only. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/

    C++17 Compiler: Microsoft VS2017 (15.3.4)

  7. #7
    Join Date
    Jul 2017
    Posts
    12

    Red face Re: template function in non-template class

    Thank you very much, @2kaud. You have given me a lot of your precious time. I hope I could be able to return you the favor.
    Thank you again.

  8. #8
    Join Date
    Jul 2017
    Posts
    12

    Re: template function in non-template class

    Thanks, @laserlight.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This a Codeguru.com survey!


On-Demand Webinars (sponsored)