注意,使用void_t
由@TartanLlama答案是好的,因爲它是。但是,在C++ 17中,很可能會有一些標準庫幫助程序,例如is_detected_v
,它們將對void_t
進行調用。
#include <experimental/type_traits>
// helpers to reduce boilerplate
template<class Tag>
struct empty_base {};
template<template<class> class Holder, template<class> class Op, class Arg>
using inject_or_t = std::conditional_t
<
std::experimental::is_detected_v<Op, Arg>,
Holder<Arg>,
empty_base<Op<Arg>>
>;
// add detector + holder for every conditional nested type
template<class T>
using foo_t = typename T::foo;
template<class T>
struct foo_holder { using foo = foo_t<T>; };
template<class T>
using bar_t = typename T::bar;
template<class T>
struct bar_holder { using bar = bar_t<T>; };
template<class T>
using baz_t = typename T::baz;
template<class T>
struct baz_holder { using baz = baz_t<T>; };
// wrapper is now simply:
template<class T>
struct wrapper
: inject_or_t<foo_holder, foo_t, T>
, inject_or_t<bar_holder, bar_t, T>
, inject_or_t<baz_holder, baz_t, T>
{};
struct Test
{
using foo = int;
using bar = int;
using baz = int;
};
int main()
{
static_assert(!std::experimental::is_detected_v<foo_t, wrapper<int>>);
static_assert(!std::experimental::is_detected_v<bar_t, wrapper<int>>);
static_assert(!std::experimental::is_detected_v<baz_t, wrapper<int>>);
static_assert(std::experimental::is_detected_v<foo_t, wrapper<Test>>);
static_assert(std::experimental::is_detected_v<bar_t, wrapper<Test>>);
static_assert(std::experimental::is_detected_v<baz_t, wrapper<Test>>);
}
Live Example注意,他是非常罕見的例子,其中的libstdC++ 6.0 SVN主幹可以(現在!)做在libC++ 3.9 SVN主幹可以不是一個。
這需要爲每個要注入的類型添加探測器別名和持有者結構,並且完全消除了對宏包裝器的需要。
這就是我想到的解決方案,我準備嘗試它。它不是很漂亮,但是比其他解決方案更容易維護,而不會將無用的東西暴露給用戶。謝謝:) – Morwenn
當。我希望能有比這更好的解決方案。 – Justin