我有这样一个类型:
template<typename T>
struct wrapper
{
using foo = typename T::foo;
using bar = typename T::bar;
using baz = typename T::baz;
// More of those...
};我希望定义foo、bar、baz和等效类型别名的条件是,只有当等效类型存在于T中时。使用std::conditional的解决方案允许在不存在时将其替换为其他类型,但当模板类型中不存在对应的类型时,我不知道如何确保它根本不存在。当wrapper<T>被实例化时,上面的代码会导致一个错误,如果T没有定义一个类型别名。
我不能让wrapper继承T,因为wrapper不应该做T能做的所有事情。此外,使用部分专门化会导致某种指数爆炸,并将很快变得不可维护。我可能会让foo,bar..。模板类型别名将std::enable_if注入到默认的模板参数中,但是用户将不得不编写wrapper<T>::foo<>、wrapper<T>::bar<>而不是wrapper<T>::foo、wrapper<T>::bar等.我不想那样。
在T中存在对应的类型别名时,是否有一种简单而可维护的方法来定义这样的类型别名?
发布于 2016-01-19 19:15:06
请注意,使用@TartanLlama使用void_t的答案是很好的。但是,在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注意: his是libstdc++ 6.0SVN主干可以使用的一个非常罕见的例子(目前!)做一些libc++ 3.9svn主干无法做的事情。
这需要为每种注入类型添加一个检测器别名和一个持卡器结构,并且完全不需要宏包装器。
https://stackoverflow.com/questions/34632416
复制相似问题