I am getting a compiler error when I am trying to compile with specific compiler version.
ie. icc 17.0 with -std=c++17 -O3
Compiler Error:
source>(19): error: no suitable user-defined conversion from "Data" to "std::__cxx11::string" exists
Data temp{std::forward<Data>(d)};
^
compilation aborted for <source> (code 2)
ASM generation compiler returned: 2
<source>(19): error: no suitable user-defined conversion from "Data" to "std::__cxx11::string" exists
Data temp{std::forward<Data>(d)};
^
compilation aborted for <source> (code 2)
Execution build compiler returned: 2
Code:
#include <string>
#include <vector>
#include <iostream>
struct Data {
std::string id{};
std::string rowData{};
int totalRawDataLength{};
std::vector<int> rawDataOffset{};
std::vector<int> rawDataLength{};
Data() = default;
Data(const Data&d) =default;
Data(Data &&d) =default;
};
Data ProcessData(Data &&d) {
Data temp{std::forward<Data>(d)};
// some code
return temp;
}
int main() {
Data d{};
d.id = "id_001";
d.rowData = "some data";
d.rawDataOffset.emplace_back(4);
d.rawDataLength.emplace_back(4);
auto x = ProcessData(std::move(d));
std::cout << "Test:" << x.id << std::endl;
return 0;
}
following code works for all version of gcc
and it works with the higher version of icc with same compiler options.
it even works for -std=c++11 -O3
for icc 17.0
on further debugging found out that something is wrong with default copy constructor which is being generated.
I am not able to understand what's wrong happening here, is it some kind of compiler bug which got resolved in later releases?
This is yet another curious example of when the fickle aggregate strikes, here alongside an arguable bug in the ICC compiler (version 17.0).
Data
is an aggregate class in C++14 and C++17 (but not in C++11)In C++11, an aggregate class was defined as, as per [dcl.init.aggr]/1 (N3337) [emphasis mine]:
An aggregate is an array or a class (Clause [class]) with no user-provided constructors ([class.ctor]), no brace-or-equal-initializers for non-static data members ([class.mem]), no private or protected non-static data members (Clause [class.access]), no base classes (Clause [class.derived]), and no virtual functions ([class.virtual]).
In C++14 and C++17, except for some explicit
details in the latter, the rules are mostly the same as in C++11, except that the requirement
[...] no brace-or-equal-initializers for non-static data members
has been removed.
Thus, as your class Data
have no user-provided constructors (see [dcl.fct.def.default]/4) and moreover only public data members, it is an aggregate in C++14 and C++17, whereas, due to its default member initializers, it is not an aggregate in C++11.
Data
is an aggregateNow, the follow direct-braced-init initialization
Data temp{std::forward<Data>(d)}
will enumerate constructor overloads in C++11, whereas in C++14 and C++17 it is direct initialization, particularly by the following rule (from cppreference:
The effects of list initialization of an object of type T are:
- If T is an aggregate class and the initializer list has a single element of the same or derived type (possibly cv-qualified), the object is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization).
If the conditions of the bullet above does not apply, direct-brace-init for an aggregate class will be aggregate initialization. This should not happen here, but ICC seemingly wrongly apply aggregate initialization in C++14 and C++17 (where Data
is an aggregate class), using std::forward<Data>(d)
to direct-initialize the first data member of Data
(namely the data member id
which is of type std::string
) rather than direct-initialization of Data
itself; all the other data members are initialized by their associated default member initializers.
[...] on further debugging found out that something is wrong with default copy constructor which is being generated.
In the example you show here you have simply provided your own copy-constructor, as compared to explicitly-defaulting it at its first declaration. This means the class Data
is no longer an aggregate (in any of C++11 through C++17).
Note that as per C++20 most of the aggregate confusion has been resolved, as per the implementation of P1008R1 (Prohibit aggregates with user-declared constructors), specifically by no longer allowing aggregates to have user-declared constructors, a stricter requirement for a class to be an aggregate than just prohibiting user-provided constructors.