Study notes on C++ implicit conversion

  • 2020-07-21 09:32:08
  • OfStack

1 operator implicit type conversion

1.1 std::ref source code reference_wrapper implicit type conversion

In the implementation of std::ref there is one piece of code:


template<typename _Tp>
 class reference_wrapper
 : public _Reference_wrapper_base<typename remove_cv<_Tp>::type>
 {
  _Tp* _M_data;

 public:
  typedef _Tp type;

  reference_wrapper(_Tp& __indata) noexcept
  : _M_data(std::__addressof(__indata))
  { }

  reference_wrapper(_Tp&&) = delete;

  reference_wrapper(const reference_wrapper&) = default;

  reference_wrapper&
  operator=(const reference_wrapper&) = default;
  //operator Implicit type conversion 
  operator _Tp&() const noexcept
  { return this->get(); }

  _Tp&
  get() const noexcept
  { return *_M_data; }

  template<typename... _Args>
 typename result_of<_Tp&(_Args&&...)>::type
 operator()(_Args&&... __args) const
 {
  return __invoke(get(), std::forward<_Args>(__args)...);
 }
 };

Note the operator operator overload:


operator _Tp&() const noexcept
  { return this->get(); }

It's used for type conversion.

1.2 Simple example - Implementation of an class to int example


#include <iostream>
/*
 *
 * c++ operator Implicit type conversion 
 *  see std::ref The implementation of the 
 */ 
void f(int a)
{
 std::cout << "a = " << a << std::endl;
}
class A{
 public:
 A(int a):num(a){}
 ~A() {}

 operator int()
 {
  return num;
 }
 int num;
};

int main()
{
 A a(1);
 std::cout << a + 1 << std::endl;
 f(a);
 return 0;
}

Of course, in addition to implicit casting via operator, c++ can also be implemented via constructors.

The 2 constructor implements implicit type conversion

c++ primer1

[

A constructor that can be called with a single argument defines a transformation from a parameter type to that type

]

Take the following example:


#include <iostream>
/*
 *
 * c++  Constructed implicit type conversion 
 *  see std::ref The implementation of the 
 */
class B{
 public:
 B(int a):num(a){}
 ~B() {}

 int num;
};

class A{
 public:
 A(int a):num(a){}
 A(B b):num(b.num){}
 ~A() {}

 int fun(A a)
 {
  std::cout << num + a.num << std::endl;
 }

 int num;
};

int main()
{
 B b(1);
 A a(2);
 // Implicit type conversion is implemented through constructors 
 a.fun(b); // The output result is 3
 return 0;
}

It is important to note that a single argument is an implicit transformation of the constructor, and that one condition is not satisfied.

3 Use the explicit keyword to avoid constructor implicit conversions

There are times when implicit conversions are not desirable and unexpected results may occur. The explicit keyword can prohibit such implicit conversions. Change the constructor of the above class A to the following


class A{
 public:
 A(int a):num(a){}
 explicit A(B b):num(b.num){}
 ~A() {}

 int fun(A a)
 {
  std::cout << num + a.num << std::endl;
 }

 int num;
};

Running the program again will prompt:

[

cpp: In function 'int main()':
op2.cpp:29:12: error: no function for call 'A::fun(B & )'
a.fun(b);
^
op2.cpp:16:9: note: candidate: int A::fun(A)
int fun(A a)
^~~
op2.cpp:16:9: note no known argument 1 from 'B' to' A'

]

At this time, the invocation mode is changed to:


int main()
{
 B b(1);
 A a(2);
 a.fun(A(b));
 return 0;
}

I can only marvel at the vastness and depth of C++ language, and this article is just an introduction to implicit conversion.

Reference:

C++ Primer implicit type conversion learning arrangement

That's all for C++ and more on C++.


Related articles: