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

C++C++11

C++ Problem Overview


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;
}

C++ Solutions


Solution 1 - C++

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

Solution 2 - C++

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

Solution 3 - C++

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

Solution 4 - C++

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);
}

Solution 5 - C++

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

Solution 6 - C++

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

A(double) = delete;

Solution 7 - C++

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGurpreet DhamiView Question on Stackoverflow
Solution 1 - C++YSCView Answer on Stackoverflow
Solution 2 - C++NathanOliverView Answer on Stackoverflow
Solution 3 - C++IHopeImHelpfulView Answer on Stackoverflow
Solution 4 - C++bracco23View Answer on Stackoverflow
Solution 5 - C++RiaDView Answer on Stackoverflow
Solution 6 - C++Hatted RoosterView Answer on Stackoverflow
Solution 7 - C++TiphaineView Answer on Stackoverflow