【问题标题】:Retrieve the template a type is instantiated from检索从中实例化类型的模板
【发布时间】:2016-06-23 22:12:17
【问题描述】:

如何检索最初实例化类型的模板?

我想做以下事情:

struct Baz{};
struct Bar{};

template <typename T>
struct Foo {};

using SomeType = Foo<Bar>;

template <typename T>
using Template = get_template<SomeType>::template type<T>;

static_assert(std::is_same<Foo<Baz>, Template<Baz>>::value, "");

我知道我可以通过部分专业化来实现这一点,但这迫使我将 get_template 专门用于我想使用的每个模板:

template <typename T>
struct get_template;

template <typename T>
struct get_template<Foo<T>>
{
    template <typename X>
    using type = Foo<X>;
};

live example

有没有办法绕过这个限制?

【问题讨论】:

  • Get the Type of a Parent的可能重复
  • 这个例子有点做作,因为你使用了别名。 "SomeType" 已经与 "Foo" (static_assert(std::is_same&lt;SomeType, Foo&lt;Bar&gt;&gt;::value, "");) 相同。也许您实际上只希望恢复 Foo 部分,因为您想将其实例化为另一种类型?
  • @AndyG 是的,我最终想用另一种类型实例化它,我编辑了问题

标签: c++ templates c++14


【解决方案1】:

您可以使用template template parameter 执行类似操作(应该适用于具有任意数量的 type 参数的模板):

template <typename T>
  struct get_template;

template <template <class...> class Y, typename... Args>
  struct get_template<Y<Args...>> {
    template <typename... Others>
    using type = Y<Others...>;
  };

然后获取模板:

template <typename T>
using Template = typename get_template<SomeType>::type<T>;

正如@Yakk 在评论中提到的那样,以上仅适用于只有类型参数的模板。您可以专门针对具有特定类型和非类型参数模式的模板,例如:

// Note: You need the first size_t to avoid ambiguity with the first specialization
template <template <class, size_t, size_t...> class Y, typename A, size_t... Sizes>
  struct get_template<Y<A, Sizes...>> {
    template <class U, size_t... OSizes>
    using type = Y<U, OSizes...>;
  };

...但您无法将其专门用于任意模板。


DEMO(与Foostd::pair):

#include <type_traits>
#include <map>

struct Bar{};

template <typename T>
struct Foo {};

using SomeType = Foo<Bar>;

template <typename T>
  struct get_template;

template <template <class...> class Y, typename... Args>
  struct get_template<Y<Args...>> {
    template <typename... Others>
    using type = Y<Others...>;
  };

template <typename T>
using Template = typename get_template<SomeType>::type<T>;

static_assert(std::is_same<SomeType, Template<Bar>>::value, "");
static_assert(std::is_same<Foo<int>, Template<int>>::value, "");

using PairIntInt = std::pair<int, int>;
using PairIntDouble = std::pair<int, double>;

template <typename U1, typename U2>
using HopeItIsPair = 
  typename get_template<PairIntDouble>::type<U1, U2>;

static_assert(std::is_same<PairIntDouble, HopeItIsPair<int, double>>::value, "");
static_assert(std::is_same<PairIntInt, HopeItIsPair<int, int>>::value, "");

【讨论】:

  • 当然,这只适用于只接受类型的模板,或者模板的有限模式。
  • @Yakk 是的......我认为没有办法让它适用于任何类型的模板(特别是如果你有交错类型和非类型参数)。尽管如此,如果您有一些关于模板参数模式的信息,您可以轻松地调整上述代码以满足您的需求。
【解决方案2】:

不确定我是否得到了问题。这行得通吗?

#include<type_traits>
#include<utility>

template<typename V, template<typename> class T, typename U>
auto get_template(T<U>) { return T<V>{}; }

struct Baz{};
struct Bar{};

template <typename T>
struct Foo {};

using SomeType = Foo<Bar>;

template <typename T>
using Template = decltype(get_template<T>(SomeType{}));

int main() {
    static_assert(std::is_same<Foo<Baz>, Template<Baz>>::value, "");
}

您可以进行更多的概括(例如,SomeType 可以是 Template 的模板参数),但它可以让您了解方法是什么。

【讨论】:

    猜你喜欢
    • 2021-01-18
    • 2016-03-16
    • 2018-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多