将指定的模板类型作为模板参数传递

Das*_*kie 5 c++ templates template-templates c++14

说我有一些模板类型......

template <typename T> struct Foo {
    Foo(T t) {}
};
Run Code Online (Sandbox Code Playgroud)

有没有办法将指定的Foo类型传递给函数,以便函数可以直接看到T?

理想情况下,我可以写这样的东西......

Foo<int> foo = create<Foo<int>>();
Run Code Online (Sandbox Code Playgroud)

我能来的最接近的是

template <
    template <typename> typename TT,
    typename T,
    std::enable_if_t<std::is_same<TT<T>, Foo<T>>::value, int> = 0
>
Foo<T> create() {
    return Foo<T>(T());
}
Run Code Online (Sandbox Code Playgroud)

然后将使用像

Foo<int> foo = create<Foo, int>();
Run Code Online (Sandbox Code Playgroud)

谢谢你的帮助.

Gui*_*cot 6

这种形式的模板模板参数仅在C++ 17中允许:

template < //           v---------- typename here not allowed
    template <typename> typename TT,
    typename T,
    std::enable_if_t<std::is_same<TT<T>, Foo<T>>::value, int> = 0
>
Foo<T> create() {
    return Foo<T>(T());
}
Run Code Online (Sandbox Code Playgroud)

你必须更换typename指出的class:

template < //           v---------- class allowed
    template <typename> class TT,
    typename T,
    std::enable_if_t<std::is_same<TT<T>, Foo<T>>::value, int> = 0
>
Foo<T> create() {
    return Foo<T>(T());
}
Run Code Online (Sandbox Code Playgroud)

在C++ 17中,两者都编译并且是等价的.


要使您的语法Foo<int> foo = create<Foo<int>>();有效,您只需要这样做:

template <typename T>
T create() {
    return T{};
}
Run Code Online (Sandbox Code Playgroud)

如果要限制可以发送的类型,则必须创建类型特征:

// default case has no typedef
template<typename>
struct first_param {};

// when a template is sent, define the typedef `type` to be equal to T
template<template<typename> class TT, typename T>
struct first_param<TT<T>> {
    using type = T;
};

// template alias to omit `typename` everywhere we want to use the trait.
template<typename T>
using first_param_t = typename first_param<T>::type;
Run Code Online (Sandbox Code Playgroud)

然后,使用你的特质:

template <
    typename T, 
    void_t<first_param_t<T>>* = nullptr
> //       ^---- if the typedef is not defined, it's a subtitution error.
T create() {
    return T(first_param_t<T>{});
}
Run Code Online (Sandbox Code Playgroud)

你可以void_t像这样实现:

template<typename...>
using void_t = void;
Run Code Online (Sandbox Code Playgroud)

Live at Coliru