Gurpreet Dhami
Gurpreet Dhami

Reputation: 681

Avoiding implicit conversion in constructor. The 'explicit' keyword doesn't help here

I am able to avoid the implicit conversion of a constructor using the explicit keyword. So now, conversions like A a1 = 10; can be avoided.

But still I can initialize A a1 = A(20.2);. How can I disable the object creation such that an object can only be created if we pass an integer as a parameter e.g. A a1 = A(10)?

#include <iostream>

class A
{
public:
    explicit A(int a)
    {
        num = a;
    }

    int num;
};

int main()
{
    A a1 = A(10.0);
    std::cout << a1.num;
    return 0;
}

Upvotes: 56

Views: 4864

Answers (7)

RiaD
RiaD

Reputation: 47620

To avoid int->double conversions everywhere, not only in your case. With g++ you can use -Wconversion -Werror. Note that it'll be allowed in your particular case, because the compiler understands that 10.0 is literal, but it will fail compilation for:

class A
{
public:
    explicit A(int a)
    {
        num = a;
    }

    int num;
};

int main()
{
    double x = 10;
    A a1 = A(x);
    static_cast<void>(a1);
    return 0;
}

Compiler explorer

Upvotes: 5

Tiphaine
Tiphaine

Reputation: 193

You should use the -Wconversion flag of gcc, that will generate a warning when implicitly casting a float to an int. Add -Werror to transform this warning (all in fact) into an error.

Upvotes: 4

IHopeImHelpful
IHopeImHelpful

Reputation: 91

You can circumvent this problem by using braced initialization. For example:

struct A {
  A(int _a) : a(_a) {}
  int a;
};

A a{5}; // ok
A b{1.123}; // compile error

Proof

Upvotes: 9

bracco23
bracco23

Reputation: 2211

I just want to add that the A(double) = delete is a C++11 addition.

If for whatever reason you cannot use this relatively new construct, you can simply declare it as private as this:

class A{
  public:
    A(int);
  private:
    A(double);
}

Upvotes: 6

YSC
YSC

Reputation: 40080

You can delete A::A(<anything not an int>);:

struct A
{
    explicit A(int a)
    : num(a)
    {}

    template<class T>
    A(T) = delete;

    int num;
};

int main()
{
    //A a1=A(10.0); // error: use of deleted function 'A::A(T) [with T = double]'
    A a2 = A(10); // OK
    (void) a2;
}

Demo: https://coliru.stacked-crooked.com/a/425afc19003697c9

Upvotes: 76

NathanOliver
NathanOliver

Reputation: 180595

The way to achieve this is to provide another constructor that would be a better match, and then delete it so you'll get an error. For your class, adding

template <typename T>
A(T) = delete;

Will stop the class from being constructed from anything that isn't an int

Upvotes: 31

Hatted Rooster
Hatted Rooster

Reputation: 36483

Explicitly delete the constructor for double (possibly add float):

A(double) = delete;

Upvotes: 4

Related Questions