从传递给模板函数的内部 class 实例中提取外部 class 类型
Extract outer class type from inner class instance passed to template function
我有一组 classes 并且在每个里面都定义了一个嵌套的 class 总是具有相同的名称。
class A {
public:
class Common {};
...
};
class B {
public:
class Common {};
...
};
我正在尝试编写这样的模板函数(不编译代码):
template<typename T, typename... ARGS>
void foo(T::Common tc, ARGS... args) {
T t(tc, args...);
// do stuff
}
我想按如下方式使用它:
{
...
A::Common ac();
foo(ac, 42, "Hello");
....
}
如何从传递给函数的内部 class 实例的类型中提取外部 class 类型?也许 <traits>
,但我是新手...
在您的以下函数模板中:
template<typename T, typename... ARGS>
void foo(T::Common tc, ARGS... args);
T
处于 non-deducible 上下文中。因此,做:
foo(ac, 42, "Hello");
无法编译,因为 T
无法从函数调用参数中推导出来。您需要将 A
作为参数显式传递给 T
模板参数:
foo<A>(ac, 42, "Hello");
但是,请注意 T::Common
实际上必须以关键字 typename
开头,因为 Common
是一个 type-dependent 名称:
template<typename T, typename... ARGS>
void foo(typename T::Common tc, ARGS... args);
在不放弃隐式类型推导的情况下提取外部 class 类型
您可以声明一个 outer_class_of<>
class 模板来提取外部 class。该模板将由内部 class 类型参数化:
// primary template
template<typename>
struct outer_class_of;
然后,将此模板专门用于 A::Common
和 B:Common
:
// specialization for A::Common
template<>
struct outer_class_of<A::Common> {
using type = A; // outer class of A::Common
};
// specialization for B::Common
template<>
struct outer_class_of<B::Common> {
using type = B; // outer class of B::Common
};
然后您可以声明一个别名模板以实现类 C++14 _t
类型特征:
template<typename T>
using outer_class_of_t = typename outer_class_of<T>::type;
这样,outer_class_of_t<A::Common>
对应A
,outer_class_of_t<B::Common>
对应B
。
最后,您需要将 foo()
函数模板定义更改为:
template<typename TCommon, typename... ARGS>
void foo(TCommon tc, ARGS... args) {
outer_class_of_t<TCommon> t(tc, args...);
}
当使用 A::Common
或 B::Common
对象作为函数参数调用 foo()
时,TCommon
将推导为 A::Common
或 B::Common
, 分别。 outer_class_of<>
然后应用于 TCommon
以获得外部 class.
的类型
此外,请注意 C++'s most vexing parse 中的:
A::Common ac();
你要的其实是:
A::Common ac{};
否则,在对 foo()
的调用中,TCommon
将被推导为 A::Common(*)()
(即:指向函数的指针)而不是 A::Common
,因为前者正在声明一个不带参数的函数和 returns 一个 A::Common
对象,而后者实际上是在声明一个 A::Common
对象。
上面的答案很好,但有点复杂。
也许(您正在寻找的)更简单的答案是您可以通过显式模板规范调用而不是隐式推导来完成。这是一个在何处权衡复杂性的问题。
也许您的呼叫者可以在呼叫中指定 A 并写入:
foo(ac, 42, "Hello");
您仍然应该放入 typename 关键字和一个好的评论来帮助您的界面用户
template<typename T, typename... ARGS>
void foo(typename T::Common tc, ARGS... args); /// Call with foo<T>(tc, ...)
我有一组 classes 并且在每个里面都定义了一个嵌套的 class 总是具有相同的名称。
class A {
public:
class Common {};
...
};
class B {
public:
class Common {};
...
};
我正在尝试编写这样的模板函数(不编译代码):
template<typename T, typename... ARGS>
void foo(T::Common tc, ARGS... args) {
T t(tc, args...);
// do stuff
}
我想按如下方式使用它:
{
...
A::Common ac();
foo(ac, 42, "Hello");
....
}
如何从传递给函数的内部 class 实例的类型中提取外部 class 类型?也许 <traits>
,但我是新手...
在您的以下函数模板中:
template<typename T, typename... ARGS>
void foo(T::Common tc, ARGS... args);
T
处于 non-deducible 上下文中。因此,做:
foo(ac, 42, "Hello");
无法编译,因为 T
无法从函数调用参数中推导出来。您需要将 A
作为参数显式传递给 T
模板参数:
foo<A>(ac, 42, "Hello");
但是,请注意 T::Common
实际上必须以关键字 typename
开头,因为 Common
是一个 type-dependent 名称:
template<typename T, typename... ARGS>
void foo(typename T::Common tc, ARGS... args);
在不放弃隐式类型推导的情况下提取外部 class 类型
您可以声明一个 outer_class_of<>
class 模板来提取外部 class。该模板将由内部 class 类型参数化:
// primary template
template<typename>
struct outer_class_of;
然后,将此模板专门用于 A::Common
和 B:Common
:
// specialization for A::Common
template<>
struct outer_class_of<A::Common> {
using type = A; // outer class of A::Common
};
// specialization for B::Common
template<>
struct outer_class_of<B::Common> {
using type = B; // outer class of B::Common
};
然后您可以声明一个别名模板以实现类 C++14 _t
类型特征:
template<typename T>
using outer_class_of_t = typename outer_class_of<T>::type;
这样,outer_class_of_t<A::Common>
对应A
,outer_class_of_t<B::Common>
对应B
。
最后,您需要将 foo()
函数模板定义更改为:
template<typename TCommon, typename... ARGS>
void foo(TCommon tc, ARGS... args) {
outer_class_of_t<TCommon> t(tc, args...);
}
当使用 A::Common
或 B::Common
对象作为函数参数调用 foo()
时,TCommon
将推导为 A::Common
或 B::Common
, 分别。 outer_class_of<>
然后应用于 TCommon
以获得外部 class.
此外,请注意 C++'s most vexing parse 中的:
A::Common ac();
你要的其实是:
A::Common ac{};
否则,在对 foo()
的调用中,TCommon
将被推导为 A::Common(*)()
(即:指向函数的指针)而不是 A::Common
,因为前者正在声明一个不带参数的函数和 returns 一个 A::Common
对象,而后者实际上是在声明一个 A::Common
对象。
上面的答案很好,但有点复杂。
也许(您正在寻找的)更简单的答案是您可以通过显式模板规范调用而不是隐式推导来完成。这是一个在何处权衡复杂性的问题。
也许您的呼叫者可以在呼叫中指定 A 并写入:
foo(ac, 42, "Hello");
您仍然应该放入 typename 关键字和一个好的评论来帮助您的界面用户
template<typename T, typename... ARGS>
void foo(typename T::Common tc, ARGS... args); /// Call with foo<T>(tc, ...)