Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

copy initialization - conversion from 'int' to non-scalar type

I would like to know how I should define the class my_int so that the cast from int to std::complex< my_int > is done by the compiler instead of manually by me.

The following program does not compile if 4 is not casted to "my_int"

// Example program
#include <iostream>
#include <string>
#include <complex>

struct my_int
{
    my_int() : _i(0) {}
    my_int(const my_int& mi) : _i(mi._i) {}

    my_int(int i) : _i(i) {}
    operator int(){return _i;}

    int _i;
};

std::ostream& operator<<(std::ostream& os, const my_int& mi)
{
    os << mi._i;
    return os;
}

int main()
{
  std::complex<my_int> ci = 4; // Casting 4 to my_int works

  std::cout << ci;
}

I know that if you initialize ci with std::complex<my_int> ci(4) it works, but I want it to work with copy initialization.

like image 222
rual93 Avatar asked May 14 '18 10:05

rual93


People also ask

What is a scalar initializer in C++?

The initializer for a scalar (an object of integer type including booleans and enumerated types, floating type including complex and imaginary, and pointer type including pointer to function) must be a single expression, optionally enclosed in braces, or an empty initializer (since C23) :

What is the difference between copy initialization and direct initialization?

In addition, the implicit conversion in copy-initialization must produce T directly from the initializer, while, e.g. direct-initialization expects an implicit conversion from the initializer to an argument of T 's constructor.

Is move-initialization the same as implicit conversion?

There is no such term as move-initialization. Implicit conversion is defined in terms of copy-initialization: if an object of type T can be copy-initialized with expression E, then E is implicitly convertible to T . The equals sign, =, in copy-initialization of a named variable is not related to the assignment operator.

What rules apply when no initializer is used?

See initialization for the rules that apply when no initializer is used. As with all other initializations, expression must be a constant expression when initializing objects of static or thread-local storage duration .


2 Answers

You can define you complex class and write the constructor this way.

  Complex(int re, int im = 0);

In this case the compiler will implicitly convert int to complex on

Complex c = 5;
like image 93
Eduard Rostomyan Avatar answered Oct 13 '22 19:10

Eduard Rostomyan


The seeming problem is that more than one user-defined conversion is not allowed in the copy-initialization context, and it can be solved by using direct-initialization context, e.g.

std::complex<my_int> ci{4}; 

However, there is another hidden problem: the effect of instantiating the template complex for any type other than float, double or long double is unspecified, so you have to explicitly specialize it, as StoryTeller pointed out in the comment.

like image 38
xskxzr Avatar answered Oct 13 '22 19:10

xskxzr