簡體   English   中英

檢測 map 實現是否支持不完整類型

[英]Detect if map implementation supports incomplete types

我想看看 map 實現是否支持不完整的類型,因為 libc++ 似乎支持它們,但 stdlibc++ 不支持。

我在這里嘗試了 SFINAE,但它給出了一個編譯錯誤:

template<template<typename, typename, typename...> typename MapType, typename = void>
struct allows_incomplete : std::false_type {};

struct incomplete_type;
template<template<typename, typename, typename...> typename MapType>
struct allows_incomplete<MapType, std::void_t<decltype(MapType<std::string_view, incomplete_type>{})>> : std::true_type {};

static_assert(allows_incomplete<std::map>::value);
static_assert(!allows_incomplete<std::unordered_map>::value);

我想看看 map 實現是否支持不完整的類型,因為 libc++ 似乎支持它們,但 stdlibc++ 不支持。

這基本上是不可能的。

首先,因為 class 模板的成員函數是延遲實例化的,所以對不完整類型的“支持”不是二元的是或否。 也許可以實例化 class,但不能使用它。 也許可以默認構造 class,但不能復制它。 至少一些成員函數通常將完整性作為先決條件。

該問題測試默認的可構造性。 然而,評論表明實際的願望是定義一個以 map 作為成員的類型,這只需要實例化。 例如,要對此進行測試,請將M{}替換為類型名稱typename M::value_type ,其中M是 map 類型。

其次,要用SFINAE測試這個,一張劇照需要class模板作者的支持。 SFINAE 僅測試直接上下文中的故障。 任何其他錯誤仍然是硬錯誤。 這些是來自 libstdc++ 的錯誤類型。 這也解釋了@sklott 回答中的is_constructible觀察。 這不是錯誤。

第三,出於編譯失敗以外的原因測試完整性是危險的。 class 模板的 Static 數據成員可以在翻譯單元的末尾(但在私有模塊片段之前)實例化。 無論在何處實例化,它們都必須給出相同的答案。 如果有一個假設的is_complete_v<T> ,任何用T incomplete 實例化它的翻譯單元都不能完成T 任何完成T的翻譯單元不得包含依賴於is_complete_v<T>的聲明。 雖然可能,但這將非常脆弱。

第四,標准 C++ 表示未定義以不完整類型實例化std::mapstd::unordered_map 編譯失敗實際上是一個不錯的選擇,而不是走進陷阱。

第二點、第三點和第四點的結果是,您只能在同意讓您作為標准 C++ 的擴展的實現上執行此操作。

libc++ 支持實例化作為擴展。 請參閱此處此處 我找不到擴展的文檔,但它在測試套件中。

所以唯一真正的解決方案是:

#include <version>
#ifdef _LIBCPP_VERSION

要檢查 map 是否支持不完整類型,您需要確定 map 本身是否為完整類型。 完整類型和不完整類型之間的唯一區別是無法獲取不完整類型的大小,即無法獲取不完整類型的sizeof() 因此,我們可以基於此構建不完整類型的檢測器。 像這樣:

#include <type_traits>
#include <map>
#include <unordered_map>
#include <iostream>

namespace detail {
    template<int N>
    struct test {using type = void;};
}

template<typename T, typename = void>
struct is_complete : std::false_type {};

template<typename T>
struct is_complete<T, typename detail::test<sizeof(T)>::type> : std::true_type {};

struct incomplete_type;
struct complete_type {};

template<template<typename, typename, typename...> typename MapType>
using allows_incomplete = is_complete<MapType<int, incomplete_type>>;

int main()
{
    std::cout << std::boolalpha << is_complete<incomplete_type>::value << std::endl;
    std::cout << std::boolalpha << is_complete<complete_type>::value << std::endl;
    std::cout << std::boolalpha << is_complete<std::map<int, incomplete_type>>::value << std::endl;
    std::cout << std::boolalpha << is_complete<std::unordered_map<int, incomplete_type>>::value << std::endl;
    std::cout << std::boolalpha << allows_incomplete<std::map>::value << std::endl;
    std::cout << std::boolalpha << allows_incomplete<std::unordered_map>::value << std::endl;
}

順便說一句,GCC 11.3 似乎有錯誤,因為即使是std::is_constructible<std::unordered_map<int, incomplete_type>>::value也會給出同樣的錯誤,這絕對是不正確的。

暫無
暫無

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

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