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

C/Cpp Apr 10, 2022

這是最近在檢查自動化測試的版本時遇到的問題,發現之前用來檢查我們的最低要求的環境已經撤掉了,所以我們並沒有測試到我們所提的最低要求編譯器版本 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 來測試 https://godbolt.org/z/8efnsd716

範例程式碼

#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 時, = {...} 這樣就會跳出錯誤了。

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

Tags

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.