Filip Czaplicki
Filip Czaplicki

Reputation: 188

Type conversion, explicit constructors etc

I have BigNum class. What exactly methods, constructors etc. I need to implement to have desired effect (like in comments)?

class BigNum {
    //...?
};

BigNum a = 1; // compiles
a = 42; // compiles
BigNum b = 1L; // compiles
BigNum c = 1U; // compiles
BigNum d = 1UL; // compiles
BigNum e = true; // doesn't compile
BigNum f = '1'; // doesn't compile

Upvotes: 0

Views: 77

Answers (4)

oo_miguel
oo_miguel

Reputation: 2379

I would recommend using a template and std::static_assert:

struct BigNum {

    template <typename Int> BigNum(Int val)
    {
        std::static_assert(std::is_integral<Int>::value,"must be integral");
        std::static_assert(!std::is_same<Int,bool>::value,"can not be bool");
        std::static_assert(!std::is_same<Int,char>::value,"can not be char");

        // ...
    }
};

You can do it analogously for the operator=.

Upvotes: 0

LogicStuff
LogicStuff

Reputation: 19607

Not so simple, actually, because bool and char will implicitly convert to other integral types. But I've made this:

class BigNum {
public:
    template <
        typename T,
        typename = typename std::enable_if<std::is_integral<T>::value &&
            !std::is_same<T, bool>::value && !std::is_same<T, char>::value>::type>
    BigNum(T) {}
};

Upvotes: 2

jensa
jensa

Reputation: 2890

Given this

a = 42; //compiles

you also need an assignment operator. Simple example:

BigNum& operator=(const int n)
{
    // relevant stuff here...
    return *this;
}

Upvotes: -1

Brian Bi
Brian Bi

Reputation: 119184

BigNum a = 1; //compiles
BigNum b = 1L; //compiles
BigNum c = 1U; //compiles
BigNum d = 1UL; //compiles
BigNum e = true; //doesn't compile
BigNum f = '1'; //doesn't compile

For these you need non-explicit constructors that will accept integral types except bool and char. You can write a full set of integral overloads like those of std::to_string. Note that you don't need overloads for types smaller than int because they can be promoted to either int or unsigned int without ambiguity. You can delegate all of these calls to the long long and unsigned long long versions and only implement those two.

// remember to define these
BigNum(unsigned long long x);
BigNum(long long x);
BigNum(unsigned long x);
BigNum(long x);
BigNum(unsigned int x);
BigNum(int x);

To disable bool and char, you can delete those constructors. Then there will be an error for those lines you want errors for. If you don't do this, they'll just get promoted to int so there won't be an error.

BigNum(bool x) = delete;
BigNum(char x) = delete;
// you might also want to delete these:
// BigNum(char16_t x) = delete;
// BigNum(char32_t x) = delete;

Another approach is to define one constructor template that accepts any integral type, then define additional deleted overloads for bool and char as before. This avoids having to write multiple implementations.

template <typename Integral, typename = std::enable_if_t<std::is_integral<Integral>::value>>
BigNum(Integral i);
BigNum(bool b) = delete;
BigNum(char c) = delete;
a = 42; //compiles

For this you need assignment operators. You probably just want to play the same game here.

// remember to define these
BigNum& operator=(unsigned long long x);
BigNum& operator=(long long x);
// you can delegate these to the above
BigNum& operator=(unsigned long x);
BigNum& operator=(long x);
BigNum& operator=(unsigned int x);
BigNum& operator=(int x);
BigNum& operator=(bool x) = delete;
BigNum& operator=(char x) = delete;
// BigNum& operator=(char16_t x) = delete;
// BigNum& operator=(char32_t x) = delete;

Upvotes: 3

Related Questions