我可以使用模板别名作为模板模板参数吗?

发布于 2024-12-02 22:34:12 字数 325 浏览 0 评论 0原文

我可以使用模板别名作为模板模板参数吗?

template <template <typename...> class> struct foo {};

template <typename T> using simple_ptr = std::unique_ptr<T>;

foo<std::unique_ptr> a; // this doesn't work, std::unique_ptr has two parameters
foo<simple_ptr> b; // does this work?

Can I use template aliases as template template parameters?

template <template <typename...> class> struct foo {};

template <typename T> using simple_ptr = std::unique_ptr<T>;

foo<std::unique_ptr> a; // this doesn't work, std::unique_ptr has two parameters
foo<simple_ptr> b; // does this work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

開玄 2024-12-09 22:34:12

是的,这显然是允许的。根据我能找到的即将发布的标准的最新草案,指出

模板模板参数模板参数应是类模板或别名模板的名称[...]。

不过,别名模板目前似乎很少受支持,因此您可能有使其与大多数编译器一起工作时遇到一些麻烦。

Yes, it is apparently allowed. According to the latest draft of the upcoming standard I could find, it is stated that

A template-argument for a template template-parameter shall be the name of a class template or an alias template [...].

However, alias templates seems very seldomly supported at the moment, so you might have some trouble making it work with most compilers.

千笙结 2024-12-09 22:34:12

阅读原始问题的人可能正在编写使用模板模板参数作为元函数的结构,如下面的清单所示。

template <int T>
struct integer
{
        using value = T;
};

template <class T, class U, template <class...> class Function>
struct binary_op
{
        // Works for add_1, but not add_2
        using type = typename Function<T, U>::type;

        // Works for add_2, but not add_1
        using type = Function<T, U>;
};

template <class T, class U>
struct add_1;

template <int T, int U>
struct add_1<integer<T>, integer<U>>
{
        using type = integer<T + U>;
};

template <class T, class U>
using add_2 = typename add_1<T, U>::type;

add_1add_2 都是元函数,让我们

  • 嵌套 typedef 的示例来区分 add_1 - style 元函数(c++03 支持)
  • add_2 作为模板别名样式 元函数(需要 c++11)的示例

二进制操作 struct 可以与模板别名样式嵌套 typedef-style 元函数一起使用,但不能同时使用两者。在这个答案中,我展示了如何重写此类 TMP 代码以避免此问题。

假设您希望将模板模板参数 Function 应用于值 Ts... 的参数包。要应用元函数,您需要

using type = Function<Ts...>; // template-alias style

using type = typename Function<Ts...>::type; // nested typedef style

拥有另一个通用元函数来检测传递的元函数类型并相应地应用它会很有用。

下面实现的 is_alias_metafunction 函数是此类工具的构建块:

#include <type_traits>

template <class... Ts>
struct sequence;

template <class T>
struct check
{
    static constexpr bool value = true;
};

template <
    template <class...> class Function,
    class                     S,
    class                     Check = void
>
struct is_alias_metafunction
{
    static constexpr bool value = true;
};

template <
    template <class...> class Function,
    class...                  Ts
>
struct is_alias_metafunction<
    Function,
    sequence<Ts...>,
    typename std::enable_if<
        check<typename Function<Ts...>::type>::value
    >::type
>
{
    static constexpr bool value = false;
};

现在,我们可以编写一个应用模板模板参数 Function 的元函数 apply 到参数包 Ts...,无论 Function 是模板别名还是模板结构。

template <
    bool                      IsAlias,
    template <class...> class Function,
    class                     S
>
struct apply_impl;

template <template <class...> class Function, class... Ts>
struct apply_impl<true, Function, sequence<Ts...>>
{
    using type = Function<Ts...>;
};

template <template <class...> class Function, class... Ts>
struct apply_impl<false, Function, sequence<Ts...>>
{
    using type = typename Function<Ts...>::type;
};

template <template <class...> class Function, class... Ts>
using apply = typename apply_impl<
    is_alias_metafunction<Function, sequence<Ts...>>::value,
    Function,
    sequence<Ts...>
>::type;

我们现在可以按如下方式使用 apply 元函数:

using type = apply<Function, Ts...>;

它将抽象出“旧版”元函数和现代 (c++11) 元函数之间的差异。

People who read the original question may be writing structs that use template template parameters as meta functions, as demonstrated in the listing below.

template <int T>
struct integer
{
        using value = T;
};

template <class T, class U, template <class...> class Function>
struct binary_op
{
        // Works for add_1, but not add_2
        using type = typename Function<T, U>::type;

        // Works for add_2, but not add_1
        using type = Function<T, U>;
};

template <class T, class U>
struct add_1;

template <int T, int U>
struct add_1<integer<T>, integer<U>>
{
        using type = integer<T + U>;
};

template <class T, class U>
using add_2 = typename add_1<T, U>::type;

add_1 and add_2 are both meta-functions, let's distinguish

  • add_1 as an example of nested typedef-style metafunction (which c++03 supported)
  • add_2 as an example of template alias-style metafunction (which requires c++11)

The binary_op struct can work either with template alias-style or nested typedef-style metafunctions, but not both. In this answer, I show how such TMP code can be rewritten to avoid this problem.

Suppose that you wish to apply a template template parameter Function to a parameter pack of values Ts.... To apply the metafunction, you need either

using type = Function<Ts...>; // template-alias style

or

using type = typename Function<Ts...>::type; // nested typedef style

It would be useful to have another generic metafunction that detects the kind of metafunction that was passed, and applys it accordingly.

The is_alias_metafunction function, which is implemented below, is a building block for such a facility:

#include <type_traits>

template <class... Ts>
struct sequence;

template <class T>
struct check
{
    static constexpr bool value = true;
};

template <
    template <class...> class Function,
    class                     S,
    class                     Check = void
>
struct is_alias_metafunction
{
    static constexpr bool value = true;
};

template <
    template <class...> class Function,
    class...                  Ts
>
struct is_alias_metafunction<
    Function,
    sequence<Ts...>,
    typename std::enable_if<
        check<typename Function<Ts...>::type>::value
    >::type
>
{
    static constexpr bool value = false;
};

Now, we can write a metafunction apply that applies a template template parameter Function to the parameter pack Ts..., regardless of whether Function is a template alias or a template struct.

template <
    bool                      IsAlias,
    template <class...> class Function,
    class                     S
>
struct apply_impl;

template <template <class...> class Function, class... Ts>
struct apply_impl<true, Function, sequence<Ts...>>
{
    using type = Function<Ts...>;
};

template <template <class...> class Function, class... Ts>
struct apply_impl<false, Function, sequence<Ts...>>
{
    using type = typename Function<Ts...>::type;
};

template <template <class...> class Function, class... Ts>
using apply = typename apply_impl<
    is_alias_metafunction<Function, sequence<Ts...>>::value,
    Function,
    sequence<Ts...>
>::type;

We can now use the apply metafunction as follows:

using type = apply<Function, Ts...>;

and it will abstract away the difference between 'legacy' metafunctions and modern (c++11) metafunctions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文