【问题标题】:C++: Extraction of template typesC++:模板类型的提取
【发布时间】:2020-09-18 14:40:05
【问题描述】:

我正在开发一个编译时包装库,偶然发现了从给定类型中提取模板参数类型的问题。

情况如下。我有一个不可更改的类R

template <class T>
class R {};

我还有一个不可更改的main函数:

int main()
{
    auto r = new R<int>();

    // Function that knows the type of 'r'
    create_obj<decltype(r)>();

    delete r;
    return 0;
}

create_obj 函数是我正在研究的函数。出于可视化的目的,我会这样写:

template< class C >
void create_obj()
{
    // Print the type of the function (Output: R<int>*)
    std::cout << boost::typeindex::type_id<C>().pretty_name() << std::endl;
}

问题是我需要从create_obj函数访问R类的int模板参数类型。

伪代码:

template< 
    template < class T >
    class C<T>
>
void create_obj()
{
    // Print the type of the function (Output: int)
    std::cout << boost::typeindex::type_id<T>().pretty_name() << std::endl;
}

有可能吗?我正在浏览 C++ 文档,但找不到任何方法从类定义中“分离”模板参数类型。

【问题讨论】:

  • create_obj 实际上应该引用r 还是什么?目前它不接受任何参数并且不返回任何内容,因此您想要它做什么并不完全清楚。
  • this 你在找什么吗?
  • @NathanOliver 我已经尝试过std::declval,但是这里说明为类R 的指定类型C 可能是一个非常复杂的类,不容易实例化。
  • @Useless 这正是没有引用,没有对象,什么都不能创建的关键。这个想法只是从已经存在的类型中提取一个类型。

标签: c++ templates template-meta-programming


【解决方案1】:

是的,有可能,一种方法:

template<typename T>
class R{};


template<typename C>
struct extract_impl{};

template<typename T>
struct extract_impl<R<T>>{
    using type = T;
};

template<typename C>
using extracted_type = typename extract_impl<std::remove_pointer_t<std::decay_t<C>>>::type;

template< class C >
void create_obj()
{
    static_assert(std::is_same_v<extracted_type<C>,int>);
}
int main()
{
    create_obj<R<int>>();
}

约定是R 本身会通过using 公开类型,但您写道它是不可更改的。

【讨论】:

  • 这是一个非常有趣的解决方案...我从未想过在struct extract 中明确指定类R。非常感谢,我正在考虑这是一个正确的解决方案。
  • @EugeneKolesnikov 你是对的,错过了。它也没有考虑引用或指针。我对其进行了编辑以使其更清晰。额外的using 也消除了对typename 的需要。
【解决方案2】:

我改为通过r 的类型调用create_obj()

create_obj<decltype(r)>();

你可以直接调用r,解决方法很简单

template <typename T>
void create_obj (R<T> const *)
 { /* do something with T */ }

但是如果你想调用create_obj() 只传递R&lt;T&gt; 类型(或指向R&lt;T&gt; 的类型指针)而不实例化R&lt;T&gt; 类型的对象,你可以定义一个轻量级类型包装器

template <typename>
struct typeWrapper
 { /* empty! */ };

重新定义create_obj() 接收typeWrapperR&lt;T&gt; 指针

template <typename T>
void create_obj (typeWrapper<R<T> *> const &)
 { /* do something with T */ }

并使用decltype(r)调用它

create_obj(typeWrapper<decltype(r)>{});

或直接R&lt;int&gt; *

create_obj(typeWrapper<R<int> *>{});

另一种选择是将create_obj 声明为结构/类

template <typename>
struct create_obj;

并仅定义基于 R&lt;T&gt; * 指针的特化,其中包含 static func() 方法

template <typename T>
struct create_obj<R<T> *>
 {
   static void func ()
    { /* do something with T */ } 
 };

您可以通过decltype(r)使用它

create_obj<decltype(r)>::func();

或通过R&lt;int&gt; *

create_obj<R<int> *>::func();

如果您愿意,可以在create_obj() 中插入普通(非static)方法,而不是static func() 方法;也许是operator()。但是,这样,你必须实例化一个create_obj 对象来调用该方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-20
    • 1970-01-01
    • 2023-02-07
    • 2019-09-23
    • 1970-01-01
    • 1970-01-01
    • 2011-06-30
    相关资源
    最近更新 更多