简体   繁体   中英

Does the constructor not support the specialization of template functions?

I tried to let my class's constructor function became a specialization template function, but I failed the compilation. Does the constructor not support the specialization of template functions? If do, how can I add specialization template function to my class's constructor function?

#include <iostream>
#include <vector>
using namespace std;
class Bignum {
private:
    vector<char> vec;
public:
    template <class Type> Bignum(const vector<Type> &num) {
        vec = num;
    }
    template <class Type> Bignum(Type &num) {
        while (num) {
            vec.push_back(num % 10);
            num /= 10;
        }
    }
    template <> Bignum(const string &str) {
        auto __first = str.rbegin();
        auto __last = str.rend();
        for (auto i = __first; i <= __last; ++i) {
            vec.push_back(*i);
        }
    }
    template <class Type> Bignum(const Type *__first, const Type *__last) {
        for (const Type *i = __last; i >= __first; --i) {
            vec.push_back(*i);
        }
    }
    template<> Bignum(char *__first, char *__last) {
        for (char * i = __last; i >= __first; --i) {
            vec.push_back(*i - '0');
        }
    }
    Bignum () {
        
    }
    friend ostream& operator << (ostream &os, const Bignum &num) {
        auto __first = num.vec.rbegin();
        auto __last = num.vec.rend();
        for (auto i = __first; i < __last; ++i) {
            os << (char)(*i + '0') << ' ';
        }
        os << (char)(*__last + '0') << endl;
        return os;
    }
    size_t size() const {
        return vec.size();
    }
    const char & at(const size_t &pos) const {
        return vec.at(vec.size() - pos);
    }
    const char & operator [] (const size_t &pos) {
        return vec.at(pos);
    }
};
int main(int argc, const char * argv[]) {
    
    return 0;
}

I received a compilation error at line 29 which says No function template matches function template specialization 'Bignum'.

As mentioned in the comments, you just need to remove the template <> from the constructors that do not need to be member function templates.

However, it may be beneficial to consider how to accomplish what you may be after in a more generic fashion.


How you actually intend to store the data is confusing, because your implementation does different things (some expect it to be stored in "little-endian" and others expect it in "big-endian" order). In addition, some of your functions expect the data to be stored in the range [0, 9] and others seem to expect data in the range ['0', '9'].

However, none of that is relevant to what I think is the real question, which is about the constructor interface, so I will assume that data is stored as ASCII digits ['0', '9'] and in the order they would be printed as a string - just to pick something.

I would also suggest you use a specific strong type Digit , as the internal representation, which would remove all ambiguity as to the meaning. It would also remove all change of undesired conversions.


It looks like you want to be able to create a BigNum out of anything that can be used to create a vector of char.

This constructor does that. Note that we explicitly disable taking a single integral type, because you can create a vector from one of those, but it does not seem to be what you want, since you have another constructor that appears to take an integral.

template <
    typename... ArgTs,
    std::enable_if_t<
        std::is_constructible_v<std::vector<char>, ArgTs...> &&
            not ((sizeof...(ArgTs) == 1) && ... && std::is_integral_v<ArgTs>),
        bool> = true>
explicit Bignum(ArgTs && ... args)
: vec(std::forward<ArgTs>(args)...)
{
    // If not using a strong type, should at least assert that the
    // data you get is what you expect.
    assert(vec.size() == std::count_if(
        vec.begin(),
        vec.end(),
        [](unsigned char c){ return std::isdigit(c); }));
}

Then, you can take any unsigned integral type like this (I restricted it to unsigned because it does not look like your code is prepared to handle signed values).

template <
    typename T,
    std::enable_if_t<
        std::is_integral_v<T> && std::is_unsigned_v<T>,
        bool> = true>
Bignum(T number)
{
    while (number) {
        vec.push_back((number % 10) + '0');
        number /= 10;
    }
    std::reverse(vec.begin(), vec.end());
}

And, to accept a string, you do not need a member function template...

Bignum(std::string_view s)
: Bignum(s.begin(), s.end())
{ }

Finally, I'll encourage you to become familiar with the standard algorithms. For example,

friend std::ostream & operator << (std::ostream & os, Bignum const & num)
{
    std::copy(num.vec.begin(), num.vec.end(), std::ostream_iterator<char>(os));
    return os;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM