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

时间:2017-06-12 18:39:25

标签: c++ templates c++14 template-templates

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

template <typename T> struct Foo {
    Foo(T t) {}
};

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

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

Foo<int> foo = create<Foo<int>>();

我最接近的是

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());
}

然后将像

一样使用
Foo<int> foo = create<Foo, int>();

感谢您的帮助。

4 个答案:

答案 0 :(得分: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());
}

您必须替换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());
}

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

要使语法Foo<int> foo = create<Foo<int>>();正常工作,您只需执行此操作:

template <typename T>
T create() {
    return T{};
}

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

// 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;

然后,使用你的特质:

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>{});
}

您可以像这样实施void_t

template<typename...>
using void_t = void;

Live at Coliru

答案 1 :(得分:4)

为什么不简单地使用标签调度,例如:

function_b()

答案 2 :(得分:4)

一种简单的方法是直接在Foo中添加子类型信息:

template <typename T> struct Foo {
    using type = T;
    Foo(T t) {}
};

然后

template <typename FooT>
FooT create() {
    return FooT(typename FooT::type{});
}

如果需要,您可以添加SFINAE:

template <typename FooT>
auto create()
-> decltype(FooT(typename FooT::type{}))
{
    return FooT(typename FooT::type{});
}

如果你想真正将函数限制为Foo,你必须在其上创建一个特征和SFINAE。

答案 3 :(得分:2)

在C ++ 11中

Demo

要点是要有一个名为create的入口点函数,它可以实例化create_helper结构以创建正确的类型。

我们可以使用模板特化来创建我们的结构,以便我们强制传递模板化的类。

完整代码:

template<class T>
struct create_helper
{
    static_assert(sizeof(T) == 0, "Need to pass templated type to create");
};

template <class T, template<class> class TT>
struct create_helper<TT<T>>
{
   static TT<T> apply()
   {
       return {T{}};
   }
};

template<class T>
auto create() -> decltype(create_helper<T>::apply())
{
    return create_helper<T>::apply();
}

测试:

template<class T>
struct Foo
{
     Foo(T t){std::cout << "Constructed Foo with value " << t << std::endl;}
};
int main()
{ 
    Foo<int> foo = create<Foo<int>>();
}

输出:

Constructed Foo with value 0