簡體   English   中英

“沒有用戶提供的默認構造函數”警告僅與 gcc

[英]“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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM