Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

c++11

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;
}
like image 382
Gurpreet Dhami Avatar asked Jul 31 '19 15:07

Gurpreet Dhami


People also ask

Which is keyword is used with constructors to prevent type conversion?

Explicit Keyword in C++ is used to mark constructors to not implicitly convert types in C++.

Can constructor be called implicitly?

Constructor can only be called implicitly on objects. But destructor can be called implicitly or explicitly.

What happens in implicit conversion?

An implicit conversion sequence is the sequence of conversions required to convert an argument in a function call to the type of the corresponding parameter in a function declaration. The compiler tries to determine an implicit conversion sequence for each argument.

Is implicit type conversion bad?

Everyone knows Implicit Conversion is bad. It can ruin SARGability, defeat index usage, and burn up your CPU like it needs some Valtrex.


4 Answers

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

like image 116
YSC Avatar answered Oct 23 '22 18:10

YSC


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

like image 30
NathanOliver Avatar answered Oct 23 '22 16:10

NathanOliver


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

like image 22
IHopeImHelpful Avatar answered Oct 23 '22 17:10

IHopeImHelpful


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);
}
like image 29
bracco23 Avatar answered Oct 23 '22 18:10

bracco23