そのまま@TartanLlamaによってvoid_t
を使用して答えは罰金であることに注意してください。しかし、C++では、標準ライブラリのヘルパー(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トランクが(現在は!)SVNトランクはできません++ 3.9のlibc何かを行うことができ非常に稀な例の一つであることに注意してください。
これには、検出器エイリアスとホルダー構造体をそれぞれ注入型に追加する必要があり、マクロラッパーが不要です。
これは私が念頭に置いた解決策であり、私はそれを試す準備ができました。実際にはそれほど美しいものではありませんが、他のソリューションよりもメンテナンスが容易です。ありがとう:) – Morwenn
ダング。私は、これよりも良い解決策があることを期待していました。 – Justin