编写泛型包装器:有条件地将模板参数中的不同类型映射到单个类内部类型

Writing a Generic Wrapper: Conditionally Map different Types from Template Arguments onto a Single Class-Internal Type

本文关键字:同类型 映射 类型 内部 单个类 参数 包装 泛型 有条件      更新时间:2023-10-16

TL;DR:如何根据模板实参的类型执行条件类型定义

我正在为不同的bitset实现编写包装器。我引用了std::bitset<>boost::dynamic_bitset<>。我观察到boost::dynamic_bitset<>遵循std::bitset<>的实现,例如通过调用代理类来处理由operator[]返回的索引处理,类称为reference,就像std::bitset<>一样。这很有用,因为在我的包装器中——它是用bitset类型BITSET模板化的——我可以执行

typename BITSET::reference operator[](INDEX_TYPE i)
    { return bitset[i]; }

std::bitset<>boost::dynamic_bitset<>都可以使用。

然而,也有一些特征不是这样并行化的。例如,声明boost::dynamic_bitset<> typedef std::size_t size_type;为索引类型,如下所示:

bool operator[](size_type pos) const { return test(pos); }

std::bitset<>只是使用size_t:

_GLIBCXX_CONSTEXPR bool                                                                          
operator[](size_t __position) const
{ return _Unchecked_test(__position); }

所以,在我的包装器我可以做typedef size_t INDEX_TYPE或类似的东西,但这可能不适用于另一个不使用size_t的实现,因为这两个巧合(或不)做。

显然没有真正通用的方法来做到这一点,但我至少可以有条件地定义我的INDEX_TYPE,类似于:

template <class BITSET, class T>
/**
 *
 * @tparam T Use this parameter to pass on the template parameter that
 *         was used to template BITSET
 */
class BitsetWrapper
{
public: // typedefs
    if (typeid(BITSET) == bool::dynamic_bitset<T>)
        typedef tyeanme BITSET::size_type INDEX_TYPE;
    else if (typeid(BITSET) == std::bitset<T>)
        typedef size_t INDEX_TYPE;
    else if (typeid(BITSET) == BitSet<T>) // my own implementation
        typedef BITSET::INDEX_TYPE INDEX_TYPE;
    else
        throw std::invalid_argument("unsupported type: "+typeid(BITSET).name());

上面的方法不工作,即使它看起来很笨拙。

这与我的问题无关,但为了完整起见,这是错误:

bitsetWrapper.hpp:34:5: error: expected member name or ';' after declaration specifiers
    if (typeid(BITSET) == bool::dynamic_bitset<T>)
    ^
bitsetWrapper.hpp:36:5: error: expected member name or ';' after declaration specifiers
    else if (typeid(BITSET) == std::bitset<T>)
    ^
bitsetWrapper.hpp:38:5: error: expected member name or ';' after declaration specifiers
    else if (typeid(BITSET) == BitSet<T>)
    ^
bitsetWrapper.hpp:40:5: error: expected member name or ';' after declaration specifiers
    else

我猜你不能只是把条件随机地放在函数之外的类空间中,这是我第一次尝试这样做,因为情况很奇怪。

但是如何正确地处理这个问题呢?

您不能使用if/else逻辑来定义这样的typedef。您可以使用辅助类来推导它。

template <typename T> struct TypedefSelector;
template <typename T> struct TypedefSelector<boost::dynamic_bitset<T>>
{
   using IndexType = BITSET::size_type;
};
template <typename T> struct TypedefSelector<std::bitset<T>>
{
   using IndexType = size_t;
};
template <typename T> struct TypedefSelector<BitSet<T>>
{
   using IndexType = BITSET::INDEX_TYPE;
};

然后使用:

template <class BITSET, class T>
class BitsetWrapper
{
   using INDEX_TYPE = typename TypedefSelector<T>::IndexType;
   ...
};

对于没有TypedefSelector的类型名,将得到编译时错误。