传递指定的模板类型的模板参数

问题描述:

说我有一些模板类型...传递指定的模板类型的模板参数

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

感谢您的任何帮助。

+0

所以,实质上,你需要一个'create'函数,它只需要一个'Foo '作为模板类型并返回一个'Foo '? – NathanOliver

+2

不能简单地是'美孚富= createFoo ();' - 作为构造类型永远是'美孚'呢? – axalis

+0

@axalis是的,我可以做'createFoo ()',而不是'创建>()',但是我正在寻找我可以概括为其他类型的解决方案,例如'创建>' – Daskie

此表单模板模板参数只允许在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

+0

因为它似乎编译为OP,我不认为这个问题。这个问题似乎是如何“修复”模板,以允许一个人写'Foo foo =创建>();'而不是'Foo foo =创建();' – NathanOliver

+0

@NathanOliver固定,谢谢指向出。 –

+1

太棒了。无论OP需要什么,现在都应该工作。 +1 – NathanOliver

为什么不能简单地用一个标签调度,如:

template <class> 
struct tag { }; 

template <class T> 
Foo<T> create(tag<Foo<T>>) { 
    return Foo<T>(T()); 
} 

//... 

Foo<int> foo = create(tag<Foo<int>>{}); 
+0

这绝对有效,但我正在寻找一个没有功能参数的解决方案。 – Daskie

+0

@Daskie重新考虑你的架构 - 该函数调用将被编译器优化像它不会有任何参数反正... –

在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 
+0

注意,基本模板'create_helper'不需要用'static_assert'死亡。如果你愿意,你可以添加一个'apply'功能就像我们与专业化确实创造T'的'默认实例。 [演示](https://wandbox.org/permlink/bAcedPFMk3I1svmI) – AndyG

一个简单的方法就是在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。

+0

特质和SFINAE似乎是要走的路 – Daskie