converting to std::tuple<...> from initializer list issue in gcc5

這是最近在檢查自動化測試的版本時遇到的問題,發現之前用來檢查我們的最低要求的環境已經撤掉了,所以我們並沒有測試到我們所提的最低要求編譯器版本 gcc 5.5。那把 gcc 5.5 加進去後發現在編譯過程中就會跳錯,

error: converting to std::tuple<T1, T2...> from initializer list would use the explicit constructor ... (T1 != T2)

但在 gcc 6 以上卻都沒有這個問題,先去 tuple 查也沒提到關於編譯器版本的問題,然後發現相關的 stackoverflow c++ - Initializing std::tuple from initializer list - Stack Overflow

範例 std::tuple<int, char> t = {1, '1'};

當編譯器提示到 initializer_list 就代表錯了,因為 initializer_list 只能有一個 type 但我們是要將兩個不同 type 的放進去,所以要避免這樣的問題就是直接去用 tuple 的 consturctor

例如 std::tuple<int, char> t = std::tuple<int, char>(1, '1');,這樣就不會有問題

另外一個問題是為啥其他版本的編譯器不會出現這樣的問題呢?

以下是用 Compiler Explorer 來測試 Compiler Explorer

範例程式碼

#include <tuple>
#include <iostream>

// use the initialier_list to make tuple
// unsupported in gcc 5
template <int... idx>
std::tuple<int, char> from_init_list() {
    std::tuple<int, char> t(, '1');
    return {std::get<idx>(t)...};
}

// use the tuple constructor to make tuple
template <int... idx>
std::tuple<int, char> from_constructor() {
    std::tuple<int, char> t(1, '1');
    return std::tuple<int, char>(std::get<idx>(t)...);
}

int main() {
    auto t1 = from_init_list<0, 1>();
    auto t2 = from_constructor<0, 1>();
    // unsupported in gcc 5
    std::tuple<int, char> t3 = {2, '2'};
    // uniform initialization
    std::tuple<int, char> t4{2, '2'};
    return 0;
}

第一個可以看到的是在 gcc 11 中 t3, t4 在右側是顯示一樣的,編譯器幫我們把原先不能用的方式直接像是 uniform initialization 的方式,他們所呼叫的 constructor 模式是一樣的。

第二個我們把它放到函數中間試試看,最後回傳時他們都是使用一樣的函數,所以也是編譯器幫我們處理好之前的問題。

這裡雖然是使用 gcc 11.2 版本來測試,但也可以從上方的連結進入後,自行更改 gcc 版本,當用到 gcc 5.5 時, = {...} 這樣就會跳出錯誤了。

老實說我對於編譯器實際上怎麼做的不是很了解,但應該是編譯器有幫我們處理掉這個問題,如果有其他方式了解編譯器怎麼處理這塊,再麻煩留言告訴我,感謝!