GNU/Linux:
cmake -S . -B build && cmake --build build && ./size_constructible
Windows:
cmake -S . -B build_win -G Ninja && cmake --build build_win && .\size_constructible
| template <typename T, typename = void> | |
| struct is_size_constructible : std::false_type {}; | |
| template <typename T> | |
| struct is_size_constructible<T, std::void_t<typename T::size_type>> | |
| : std::is_constructible<T, typename T::size_type> {}; | |
| template <typename T> | |
| inline constexpr bool is_size_constructible_v = is_size_constructible<T>::value; |
| # ignore build artifacts | |
| build | |
| build_win | |
| size_constructible | |
| *.exe | |
| *.ilk | |
| *.pdb |
GNU/Linux:
cmake -S . -B build && cmake --build build && ./size_constructible
Windows:
cmake -S . -B build_win -G Ninja && cmake --build build_win && .\size_constructible
| cmake_minimum_required(VERSION 3.16) | |
| project( | |
| size_constructible | |
| VERSION 0.1.0 | |
| DESCRIPTION | |
| "SFINAE approach to checking if a Container is \"size-constructible\"." | |
| HOMEPAGE_URL | |
| https://gist.github.com/phetdam/5ba39c8f7a8966ffe391612f54581a41 | |
| LANGUAGES CXX | |
| ) | |
| set(CMAKE_CXX_STANDARD 17) | |
| set(CMAKE_CXX_STANDARD_REQUIRED ON) | |
| add_executable(size_constructible size_constructible.cc) | |
| set_property( | |
| TARGET size_constructible | |
| PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR} | |
| ) |
| /** | |
| * @file size_constructible.cc | |
| * @author Derek Huang | |
| * @brief SFINAE approach to checking if a *Container* is "size-constructible" | |
| * @copyright MIT License | |
| */ | |
| #include <cstdlib> | |
| #include <iostream> | |
| #include <list> | |
| #include <type_traits> | |
| #include <typeinfo> | |
| #include <vector> | |
| // GCC, clang use Itanium ABI so typeid(T).name() returns a mangled name. on | |
| // Windows, if compiling with MSVC, typeid(T).name() returns "class T". | |
| #if defined(__GNUG__) || defined(__clang__) | |
| #include <cxxabi.h> | |
| /** | |
| * Return the demangled GCC/Clang type name for a type and set an error status. | |
| * | |
| * Since the demangled name is allocated on heap, `dest` must be freed. | |
| * | |
| * @param type C++ type name | |
| * @param status_addr `int*` address to set error status | |
| * @returns `char*` giving the demangled type name for `type` | |
| */ | |
| #define GNU_DEMANGLED_TYPE_NAME(type, status_addr) \ | |
| abi::__cxa_demangle(typeid(type).name(), NULL, NULL, status_addr) | |
| /** | |
| * Exit the program with the given error status if it is nonzero. | |
| * | |
| * @param status Error status set by `abi::__cxa_demangle` call | |
| */ | |
| #define GNU_DEMANGLE_STATUS_HANDLER(status) \ | |
| do { \ | |
| if (status) { \ | |
| std::cerr << "abi::__cxa_demangle error status " << status << std::endl; \ | |
| std::exit(status); \ | |
| } \ | |
| } \ | |
| while (0) | |
| #endif // defined(__GNUG__) || defined(__clang__) | |
| namespace { | |
| /** | |
| * Template struct to check if a *Container* is "size-constructible." | |
| * | |
| * Here "size-constructible" is taken to mean that a *Container* type `T` has a | |
| * constructor `T(size_type N)` that reserves space for `N` elements. | |
| * | |
| * When `T` has the `size_type` member, the below partial specialization will | |
| * be deduced from `is_size_constructible<T>`, which then will use | |
| * `std::is_constructible` to specialize into `std::true_type` if | |
| * `T(size_type N)` is a constructor overload, else `std::false_type`. | |
| * | |
| * `is_size_constructible_v` is an `inline constexpr bool` helper for the | |
| * `is_size_constructible<T>::value` truth value. | |
| * | |
| * @tparam T *Container* type | |
| * @tparam _ `std::void_t` | |
| */ | |
| template <typename T, typename = void> | |
| struct is_size_constructible : std::false_type {}; | |
| template <typename T> | |
| struct is_size_constructible<T, std::void_t<typename T::size_type>> | |
| : std::is_constructible<T, typename T::size_type> {}; | |
| template <typename T> | |
| inline constexpr bool is_size_constructible_v = is_size_constructible<T>::value; | |
| } // namespace | |
| int main() | |
| { | |
| using T = std::vector<double>; | |
| using U = std::list<float>; | |
| #if defined(__GNUG__) || defined(__clang__) | |
| int status; | |
| char* t_name = GNU_DEMANGLED_TYPE_NAME(T, &status); | |
| GNU_DEMANGLE_STATUS_HANDLER(status); | |
| char* u_name = GNU_DEMANGLED_TYPE_NAME(T, &status); | |
| GNU_DEMANGLE_STATUS_HANDLER(status); | |
| #else | |
| const char* t_name = typeid(T).name(); | |
| const char* u_name = typeid(U).name(); | |
| #endif // defined(__GNUG__) || defined(__clang__) | |
| static_assert(is_size_constructible_v<T> && is_size_constructible_v<U>); | |
| std::cout << t_name << " is size-constructible\n"; | |
| std::cout << u_name << " is size-constructible" << std::endl; | |
| // t_name, u_name are malloc'd and so we must free | |
| #if defined(__GNUG__) || defined(__clang__) | |
| std::free(t_name); | |
| std::free(u_name); | |
| #endif // defined(__GNUG__) || defined(__clang__) | |
| return EXIT_SUCCESS; | |
| } |