簡體   English   中英

為什么std::visit in a unsatisfied concept會導致gcc編譯錯誤

[英]Why does std::visit in an unsatisfied concept cause a compile error in gcc

這段代碼:

#include <concepts>
#include <string>
#include <variant>

struct any_callable {
public:
    template<typename T>
    void operator()(T&&) {}
};

template<typename V>
concept is_variant = requires(V v) { std::visit(any_callable{}, v); };

int main() {
    constexpr bool wrapped = is_variant<std::string>;
}

不能在 gcc 11 下編譯。它給出了一堆關於valueless_by_exception等的錯誤。 但是,它確實在 msvc ( Godbolt ) 下編譯。 現在,據我所知,在這種情況下,如果它通常無法編譯,它將衰減為 false,否則為 true。 msvc 的行為似乎支持這一點。

所以:這是 gcc 中的錯誤,msvc 的非標准功能,和/或我的代碼有錯嗎?

那個:

template<typename V>
concept is_variant = requires(V v) { std::visit(any_callable{}, v); };

完全有效是最近的變化,這是P2162的結果。 為了使此檢查工作,您需要std::visit成為通常所說的“SFINAE-friendly”。 也就是說:它必須以某種方式被限制在“變體”上,這樣如果V是變體,它就可以工作,如果V不是變體,那么visit從重載集中刪除,這樣這個調用就是一個無效的表達式(以便可以拒絕該concept )。

但是,在 P2162 之前, std::visit沒有約束 這不是 SFINAE 友好的:調用要么有效,要么格式錯誤。 正是這篇論文添加了一個約束,即您傳遞給它的類型是變體(或從一個變體)。 這就是為什么您會看到您所看到的錯誤: visit調用失敗,但不是以對concept檢查友好的方式。

在 P2162 之后(正如論文所指出的,MSVC 已經實現,但 libstdc++ 沒有實現),您的支票將有效。

但是我們可以在 C++20 中更容易地做到這一點,而無需進入變體機制 - 通過以與論文相同的方式直接檢查變體性:

template<typename V>
concept is_variant = requires(V v) {
    []<typename... Ts>(std::variant<Ts...> const&){}(v);
};

如果v是一個variant或者它繼承自一個variant ,那么該 lambda 可以用v調用。 否則,它是錯誤的。 這比通過visit更直接。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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