将指定的模板类型作为模板参数传递
Passing specified template type as template parameter
假设我有一些模板类型...
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>();
感谢您的帮助。
这种形式的模板模板参数只在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());
}
您必须替换 class
指出的 typename
:
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;
为什么不简单地使用标签调度,例如:
template <class>
struct tag { };
template <class T>
Foo<T> create(tag<Foo<T>>) {
return Foo<T>(T());
}
//...
Foo<int> foo = create(tag<Foo<int>>{});
在 C++11 中
Demo
要点是有一个名为 create
的入口点函数,它可以实例化 create_helper
结构以创建正确的类型。
我们可以使用模板特化来创建我们的结构,这样我们就可以强制传递一个模板化的 class。
完整代码:
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
一种简单的方法是直接在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。
假设我有一些模板类型...
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>();
感谢您的帮助。
这种形式的模板模板参数只在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());
}
您必须替换 class
指出的 typename
:
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;
为什么不简单地使用标签调度,例如:
template <class>
struct tag { };
template <class T>
Foo<T> create(tag<Foo<T>>) {
return Foo<T>(T());
}
//...
Foo<int> foo = create(tag<Foo<int>>{});
在 C++11 中
Demo
要点是有一个名为 create
的入口点函数,它可以实例化 create_helper
结构以创建正确的类型。
我们可以使用模板特化来创建我们的结构,这样我们就可以强制传递一个模板化的 class。
完整代码:
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
一种简单的方法是直接在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。