当前位置:  开发笔记 > 编程语言 > 正文

条件类型别名定义

如何解决《条件类型别名定义》经验,为你挑选了2个好方法。

我有这样的类型:

template
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::conditionalallow的解决方案当它不存在时用其他东西替换它,但我不知道如果模板类型中不存在相应的类型,它根本不存在.wrapper如果T没有定义其中一个类型别名,则上面的代码在实例化时会导致错误.

我不能wrapper继承,T因为wrapper不应该做所有事情都T可以.此外,使用部分专业化将导致某种指数爆炸,并很快变得不可维护.我大概可以做foo,bar...模板类型别名注入一个std::enable_if在默认模板参数,但随后用户会写wrapper::foo<>,wrapper::bar<>而不是wrapper::foo,wrapper::bar等...我不希望出现这种情况.

是否有一种简单但可维护的方法来定义这样的类型别名只有在相应的类型别名存在时T



1> TartanLlama..:

你可以定义check_foo,check_barcheck_baz特征,其只拥有类型,如果它存在,那么在所有这些继承wrapper:

template  
struct check_foo{};

template  
struct check_foo> { 
    using foo = typename T::foo; 
};

// ditto for bar, baz, etc.

template 
struct wrapper :
    check_foo,
    check_bar,
    check_baz
{ };

它是每种类型的一个额外结构,但肯定比你提到的指数版本更好.如果你恰当地反常,你甚至可以把它变成一个宏:

#define DEFINE_CHECKER(NAME) \
    template  struct check_##NAME{}; \
    template  struct check_##NAME> \
    { using NAME = typename T::NAME; };

DEFINE_CHECKER(foo)
DEFINE_CHECKER(bar)
DEFINE_CHECKER(baz)

可怕,我知道,但我认为你可能需要支付这个价格,如果你真的想要wrapper::bar而不是wrapper::bar<>.如果您使用宏版本,添加新类型将只是一个新的DEFINE_CHECKER(newname)并添加check_newname到包装器继承列表.可能更糟.

Live Demo



2> TemplateRex..:

请注意void_t@TartanLlama 使用的答案很好.但是,在C++ 17中,很可能会有一些标准库帮助程序,例如is_detected_v那些可以进行调用的标准库帮助程序void_t.

#include 

// helpers to reduce boilerplate
template
struct empty_base {};

template class Holder, template class Op, class Arg>
using inject_or_t = std::conditional_t
<
    std::experimental::is_detected_v,
    Holder,
    empty_base>
>;

// add detector + holder for every conditional nested type

template
using foo_t = typename T::foo;

template
struct foo_holder { using foo = foo_t; };

template
using bar_t = typename T::bar;

template
struct bar_holder { using bar = bar_t; };

template
using baz_t = typename T::baz;

template
struct baz_holder { using baz = baz_t; };

// wrapper is now simply:

template
struct wrapper
:   inject_or_t
,   inject_or_t
,   inject_or_t
{};

struct Test
{
    using foo = int;
    using bar = int;
    using baz = int;
};

int main()
{
    static_assert(!std::experimental::is_detected_v>);
    static_assert(!std::experimental::is_detected_v>);
    static_assert(!std::experimental::is_detected_v>);

    static_assert(std::experimental::is_detected_v>);
    static_assert(std::experimental::is_detected_v>);
    static_assert(std::experimental::is_detected_v>);
}

活生生的例子说明,他是非常罕见的例子,其中的libstdc ++ 6.0 SVN主干可以(现在!)做在libc ++ 3.9 SVN主干可以不是一个.

这需要为每个要注入的类型添加检测器别名和持有者结构,并且完全不需要宏包装器.

推荐阅读
oDavid_仔o_880
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有