![](/img/trans.png)
[英]A defaulted default constructor, why is it not a user-provided default constructor?
[英]“no user-provided default constructor” warning only with gcc
以下代碼在使用 gcc 編譯時發出警告,但僅適用於版本 <= 9.3
#include <array>
#include <iostream>
template <std::size_t size>
struct A {
using atype = std::array<double, size>;
template <std::size_t index = 0>
static constexpr void fill_array(atype& res)
{
std::get<index>(res) = 1;
if constexpr (index < (size - 1))
fill_array<index + 1>(res);
}
static constexpr atype get_array()
{
atype res;
fill_array(res);
return res;
}
};
int main()
{
auto x = A<3>::get_array();
for (const auto e: x)
std::cout << e << ' ';
}
在godbolt上測試它。 我正在使用-Wall -pedantic -std=c++17 -O3
進行編譯。 發出的警告是
In file included from <source>:1:
<source>: In instantiation of 'static constexpr A<size>::atype A<size>::get_array() [with long unsigned int size = 3; A<size>::atype = std::array<double, 3>]':
<source>:26:30: required from here
/opt/compiler-explorer/gcc-9.3.0/include/c++/9.3.0/array:94:12: note: 'using atype = struct std::array<double, 3>' {aka 'struct std::array<double, 3>'} has no user-provided default constructor
94 | struct array
| ^~~~~
/opt/compiler-explorer/gcc-9.3.0/include/c++/9.3.0/array:110:56: note: and the implicitly-defined constructor does not initialize 'double std::array<double, 3>::_M_elems [3]'
110 | typename _AT_Type::_Type _M_elems;
| ^~~~~~~~
Compiler returned: 0
雖然std::array
的 double 未初始化,但實際上遞歸模板例程初始化res
的所有元素。 因此,警告不是“真實的”。 原則上,我可以通過調用fill_array<1>
來“破解”代碼,從而跳過0
組件的初始化。 但是模板函數的代碼只有在使用給定的模板參數實例化時才會生成,所以同樣,在上面的代碼中,編譯器永遠不會跳過生成fill_array<0>
。
奇怪的是,這個警告只出現在 gcc 的 9.3 版本之前。 此外,clang 不會發出警告。 更奇怪的是,當函數沒有嵌入到 class 中時,警告消失了。 使用以下代碼:
#include <array>
#include <iostream>
constexpr std::size_t size = 3;
using atype = std::array<double, size>;
template <std::size_t index = 0>
void fill_array(atype& res)
{
std::get<index>(res) = 1;
if constexpr (index < (size - 1))
fill_array<index + 1>(res);
}
atype get_array()
{
atype res;
fill_array(res);
return res;
}
int main()
{
auto x = get_array();
for (const auto e: x)
std::cout << e << ' ';
}
盡管顯然與第一個代碼相同,但沒有顯示警告。 在這里測試一下。
兩個代碼之間的編譯器行為不同是否有原因?
我可以只針對這個變量抑制警告,而不引入開銷嗎?
它看起來像舊版本 static 分析器中的錯誤,它無法檢測到您為元素分配值並警告您使用未初始化的 class 和消息無法通過編譯器標志避免 - 禁用迂腐模式和所有警告都不會刪除它,因為 res 應該是一個返回的常量,它必須被初始化。
抑制它的最簡單方法是添加值初始化,這對編譯時初始化沒有成本:
atype res {};
此外,看起來更慣用的std::generate
將適用於 C++20。 注意 - 使用 C++17 您的 fill_array() 不是constexpr
由於返回atype res
但您沒有看到錯誤,因為您允許x
運行時。
get_array
的正確 get_array
static constexpr atype get_array()
{
atype res {};
for (std::size_t i = 0; i < size; i++)
res[i] = 1;
return res;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.