为某些外部模板类定义部分专业化,并限制模板参数

弗拉迪斯拉夫

我有班Foo和班Bar。它们是std :: array的包装器。他们两个都有一些派生类。

template<typename T, std::size_t N>
struct Foo {
    std::array<T, N> data;
};

template<typename T, std::size_t N>
struct FooDerived : Foo <T, N> {};

template<typename T, std::size_t N>
struct Bar {
    std::array<T, N> data;
};

template<typename T, std::size_t N>
struct BarDerived : Bar <T, N> {};

我想在std名称空间中实现tuple-interface:get / tuple_size / tuple_element。但是这些方法应适用于Foo并从Foo类派生。

namespace std {
template<template<typename, std::size_t> class T, typename TArg, std::size_t NArg>
class tuple_size<T<TArg, NArg>>
  : public integral_constant<std::size_t, NArg>
  {
  };

template<std::size_t I, template<typename, std::size_t> class T, typename TArg, std::size_t NArg>
struct tuple_element<I, T<TArg, NArg>>
  {
  using type = TArg;
  };
} // namespace std

可行,但也适用于Bar和Bar派生的类。

我认为可以将std :: enable_if与std :: is_base_of一起使用。类的std :: enable_if可以用作模板参数。如果我写:

template<template<typename, std::size_t> class T, typename TArg, std::size_t NArg,
    typename std::enable_if<std::is_base_of<Foo<TArg, NArg>, T<TArg, NArg>>::value, int>::type = 0>
class tuple_size<T<TArg, NArg>>
  : public integral_constant<std::size_t, NArg>
  {
  };

它会导致编译错误:默认模板参数不能在部分专业化中使用。

是否可以禁止对与Foo类无关的类使用类似tuple的接口?

例如:http//rextester.com/JEXJ27486

更新:似乎我找到了解决方案。比static_assert更灵活。如果无法在部分专业化中使用默认模板参数,请添加具有完全模板专业化的其他类。

template<typename T, typename TArg, std::size_t NArg, typename = void>
struct tuple_resolver;

template<typename T, typename TArg, std::size_t NArg>
struct tuple_resolver<T, TArg, NArg,
    typename std::enable_if<std::is_base_of<Foo<TArg, NArg>, T>::value>::type>
    : public integral_constant<std::size_t, NArg>
{
    using type = TArg;
};

template<template<typename, std::size_t> class T,
    typename TArg,
    std::size_t NArg>
class tuple_size<T<TArg, NArg>>
  : public tuple_resolver<T<TArg, NArg>, TArg, NArg>
  {
  };

例如:http//rextester.com/KTDXNJ90374

丹尼尔·谢普勒

如果您可以使用建议的但尚未标准化的语言功能,那么在gcc 6.1下使用以下-fconcepts标志似乎可以正常工作

template <typename Base, typename Derived>
concept bool BaseOf = std::is_base_of<Base, Derived>::value;

namespace std {
  template <template<typename,std::size_t> class Tmpl, typename T, std::size_t N>
  requires BaseOf<Foo<T, N>, Tmpl<T, N>>
    class tuple_size<Tmpl<T, N>>
    : public std::integral_constant<std::size_t, N>
    { };
};

// tests
static_assert(std::tuple_size<FooDerived<int, 5>>::value == 5,
              "FooDerived");
static_assert(std::tuple_size<std::array<int, 5>>::value == 5,
              "std::array");

template <typename T>
concept bool SizedTuple = requires {
  { std::tuple_size<T>::value } -> std::size_t
};
static_assert(!SizedTuple<BarDerived<int, 5>>, "BarDerived");

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章