首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么template<typename...>不能通过template<template<typename> typename>被识别为可实例化?

为什么template<typename...>不能通过template<template<typename> typename>被识别为可实例化?
EN

Stack Overflow用户
提问于 2017-02-05 04:43:26
回答 2查看 1K关注 0票数 8

我试图任意地“绑定”模板参数,但遇到了一个优雅的问题。

直截了当地说一下根本的问题,gcc 6.2有以下问题,但从逻辑上讲,我认为它没有问题。

代码语言:javascript
复制
template<template<typename, typename> P, typename A, typename B>
struct foo {
    static constexpr bool value = P<A, B>::value;
};

template<typename...Ts>
struct bar {
    static constexpr bool value = true;
};

. foo给定的bar (如foo<bar, void, void> )应该会导致bar<void, void> (这是有效的)的实例化,value成员是true,因此foo<bar, void, void>::value也是true。实际上,这应该(在我看来)导致在概念上类似于.的实例化结构。

代码语言:javascript
复制
struct bar<void, void> {
    static constexpr bool value = true;
};

struct foo<bar, void, void> {
    static constexpr bool value = bar<void, void>::value; //which is true
};

您可以在这里看到这个概念(或者更确切地说是错误),https://godbolt.org/g/lT9umg

回到现在开始的时候,首先我尝试了以下.

代码语言:javascript
复制
template<typename...>
struct type_list { };

template<template<typename...> typename Tmpl, typename...Ts>
struct bind_template {
    template<typename...Us>
    using type = Tmpl<Ts..., Us...>;
};

template<template<typename> typename Predicate, typename...Ts>
struct has_matching_type {
    private:
        template<template<typename> typename, typename, typename=void>
        struct helper: std::false_type { };
        template<template<typename> typename P, typename U, typename...Us>
        struct helper<P, type_list<U, Us...>, typename std::enable_if<P<U>::value>::type>: std::true_type { };
        template<template<typename> typename P, typename U, typename...Us>
        struct helper<P, type_list<U, Us...>, typename std::enable_if<!P<U>::value>::type>: helper<P, type_list<Us...>> { };
    public:
        static constexpr bool value = helper<Predicate, type_list<Ts...>>::value;
};

template<typename T, typename...Ts>
using has_type = has_matching_type<bind_template<std::is_same, T>::template type, Ts...>;

稍后,我可能尝试通过has_type<T, Ts...>实例化,例如..。

代码语言:javascript
复制
cout << has_type<long, int, bool, long, float>::value << endl;

但是,正如我所指出的,gcc 6.2.0抱怨说,因为它似乎没有意识到,一旦完成了解析,模板实例化就会在实用上等价。

简单地知道模板参数的数量并专门处理这个确切的数目就可以解决这个问题。如果我专攻bound_template,记住std::is_same<LHS, RHS> .

代码语言:javascript
复制
template<template<typename, typename> typename Tmpl, typename T>
struct bind_template<Tmpl, T> {
    template<typename U>
    using type = Tmpl<T, U>;
};

..。我们突然编译和评估编译时间没有问题,因为gcc将bind_template<std::is_same, long>::type视为一种精确的类型参数。

显然,将这个概念抽象出来以允许任何模板参数,例如积分常量,而不仅仅是类型,是一个根本问题,不管编译器是什么。不过,只要专注于类型一分钟,我的问题是多方面的:

  1. 我是不是在概念上遗漏了什么,而编译器实际上正在做的正是我应该看到的事情呢?
  2. 如果没有,这是否违反了C++11标准,不是由标准指导的,还是编译器依赖关系?
  3. 有没有一些优雅的方法,我可以绕过这一点,而不管我的前两个问题的答案?

在功能上,真正的问题(特别是如果这是C++11中不可避免的问题)是.

有什么优雅的方法,我可以抽象绑定模板,而不必专门针对每一种情况(这里最简单的是n个类型)?

只要能得到问题1或3的答案,那就太好了。问题3是最重要的,因为在一天结束时,最重要的是什么起作用。

显然,我可以专攻(如上面所示)。但是,一个大问题是,即使下面的内容似乎也不起作用(至少根据这个在线编译器的说法).

代码语言:javascript
复制
template<template<typename...> class Tmpl, typename... Ts>
struct bind_helper {
    template<typename... Us>
    struct type: Tmpl<Ts..., Us...> { };
    template<typename A>
    struct type<A>: Tmpl<Ts..., A> { };
    template<typename A, typename B>
    struct type<A, B>: Tmpl<Ts..., A, B> { };
    template<typename A, typename B, typename C>
    struct type<A, B, C>: Tmpl<Ts..., A, B, C> { };
};

这意味着,我不仅必须生成一组参数,而且还必须通过完全的bind_template专门化来匹配外部参数。这很快就变成(实际上)一个二项式问题。

进一步扩展这个概念(但仍然保留类型),我计划下一个实现“占位符”的方式与std::bind使用占位符的方式相同(因为我刚刚剥离并重新加入了索引中的列表),这将非常优雅地工作。显然,如果没有更抽象的方法,这是非常混乱的。

EN

回答 2

Stack Overflow用户

发布于 2017-02-07 07:22:38

这在C++17中是固定的。

模板类A{ /* . */ };template类B{ /* .Types>类C{ /* .* };模板类D{ /* .* };template类X{ /* .* };template类Q>类Y{ /* .* };template类Z{ /* .* };xa;/ OK X xb;// OK X xc;// OK Y ya;// OK Y yb;// OK Y yc;// OK Z zd;// OK Y yb;//OK Y yc;//OK Z zd;//OK Y yb;//OK Y yc;//OK Z zd;//OK Y

这里的相关示例是X<C>。这在g++ 7中与标志-std=c++1z一起工作。

C++14指定上面的示例格式不正确:

模板类A{ /∗.∗/ };template类B{ /∗.∗/ };模板<.Types>类C{ /∗.∗/ };template类X{ /∗.∗/ };template类Q>类Y{ /∗.∗/ };X xa;// OK X xb;//错误格式:模板参数参数的默认参数被忽略X xc;//错误格式:模板参数包与模板参数不匹配

这一变化发生在2016年末的“纽约时报”( 模板匹配-参数不包含兼容模板。 )上。在这个承诺从11月开始中应用了这一变化。问题是委员会自1999年或以前就知道

票数 10
EN

Stack Overflow用户

发布于 2017-02-08 16:31:02

在C++17之前,由于jbapple的回答中提到的一个不幸的语言缺陷,此代码的格式是错误的。

一个符合C++11的解决方案是从到处使用元功能到到处使用元功能类。来自Boost.mpl定义的元函数类将是一个具有名为apply的模板别名的类型。我们可以这样引用:

代码语言:javascript
复制
template <class MFC, class... Ts>
using apply_t = typename MFC::template apply<Ts...>;

我们可以通过以下方法将模板提升到元功能类:

代码语言:javascript
复制
template <template <typename...> class Z>
struct quote {
    template <class... Args>
    using apply = Z<Args...>;
};

然后,让我们重写bind_template以接受一个元功能类,而不是模板:

代码语言:javascript
复制
template <class MFC, class... Ts>
struct bind_template {
    template <class... Us>
    using apply = apply_t<MFC, Ts..., Us...>;
};

然后重写has_matching_type以接受元功能类,而不是模板:

代码语言:javascript
复制
template<class Predicate, class... Ts>
struct has_matching_type {
private:
    template<class>
    struct helper: std::false_type { };

    template<typename U, typename...Us>
    struct helper<type_list<U, Us...>>
        : std::conditional<
            apply_t<Predicate, U>::value,
            std::true_type,
            helper<type_list<Us...>>
            >::type
     { };

public:
    static constexpr bool value = helper<type_list<Ts...>>::value;
};

template<class T, class... Ts>
using has_type = has_matching_type<bind_template<quote<std::is_same>, T>, Ts...>;

现在,您的初始has_type<long, int, bool, long, float>::valuetrue,甚至在C++11中也是如此。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42048621

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档