简体   繁体   中英

simple code that compile in c++17 produce error with c++20

I have a strange error returned by gcc/clang When I switch from std=c++17 to std=c++20.

struct Matrix2 {
   double ptr[9];

   // defaults
   Matrix2()                          = default; // constructor
   Matrix2(const Matrix2&)            = default; // copy constructor
   Matrix2(Matrix2&&)                 = default; // move constructor
   Matrix2& operator=(const Matrix2&) = default; // copy assignment operator
   Matrix2& operator=(Matrix2&&)      = default; // move assignment operator
   ~Matrix2()                         = default; // destructor

};

constexpr Matrix2 Id2() {
    return {   1.0   ,   0.0   ,   0.0   ,
               0.0   ,   1.0   ,   0.0   ,
               0.0   ,   0.0   ,   1.0   };
}

int main () {
   auto a = Id2();
}

with stdc++17, the code compile fine, but with stdc++20 this produce the following error: could not convert '{1.0e+0, 0.0, 0.0, 0.0, 1.0e+0, 0.0, 0.0, 0.0, 1.0e+0}' from '<brace-enclosed initializer list>' to 'Matrix2'

https://godbolt.org/z/P4afYYn9d

Does the standard now prohibit returning raw initializer_list?? and what is the work around??

Thx a lot

There was a change in the C++ standard between C++17 and C++20 for aggregate initialization. Have a look at aggregate initialization (cppreference)

Look at the explanation section:

  • since c++11, until c++20 : no user-provided, inherited, or explicit constructors (explicitly defaulted or deleted constructors are allowed)
  • since C++20 : no user-declared or inherited constructors

You have declared constructors in your class/struct, so as of C++20 you can't have this kind of initialization. You'd have to declare your own constructor with initialization list

[edit: adding some detailed examples]

Or remove all the defaulted constructors.

You could also have a constructor from std::array :

struct Matrix2 {
   std::array<double,9> ptr;

   // defaults
   Matrix2()                          = default; // constructor
   Matrix2(const Matrix2&)            = default; // copy constructor
   Matrix2(Matrix2&&)                 = default; // move constructor
   Matrix2& operator=(const Matrix2&) = default; // copy assignment operator
   Matrix2& operator=(Matrix2&&)      = default; // move assignment operator
   constexpr Matrix2(const std::array<double, 9> & arr)
   : ptr(arr) {}
   ~Matrix2()                         = default; // destructor    
};

constexpr Matrix2 Id2() {
    // not nice, requires extra brace.
    // not nice, potentially slower if the compiler misses
    // the opportunity to elide the copy of the array.
    return {{   1.0   ,   0.0   ,   0.0   ,
               0.0   ,   1.0   ,   0.0   ,
               0.0   ,   0.0   ,   1.0   }};
}

int main () {
   auto a = Id2();
}

Or with initialization list:

struct Matrix2 {
   double ptr[9];

   // defaults
   Matrix2()                          = default; // constructor
   Matrix2(const Matrix2&)            = default; // copy constructor
   Matrix2(Matrix2&&)                 = default; // move constructor
   Matrix2& operator=(const Matrix2&) = default; // copy assignment operator
   Matrix2& operator=(Matrix2&&)      = default; // move assignment operator
   constexpr Matrix2(const std::initializer_list<double> & init)
   :ptr{}
   {
       // not nice, this is not as good as the validation 
       // the compiler does for aggregate initialization.
       assert(std::size(init) <= std::size(ptr));
       std::copy(std::begin(init), std::end(init), ptr);
   }
   ~Matrix2()                         = default; // destructor

};

constexpr Matrix2 Id2() {
    return {   1.0   ,   0.0   ,   0.0   ,
               0.0   ,   1.0   ,   0.0   ,
               0.0   ,   0.0   ,   1.0   };
}

int main () {
   auto a = Id2();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM