TL;DR: How can I perform conditional typedefs depending on the type of the template argument.
I am writing a Wrapper for different bitset implementations. For that I am referencing std::bitset<>
and boost::dynamic_bitset<>
. I observe that boost::dynamic_bitset<>
follows the implementation of std::bitset<>
by for example calling the proxy class for index handling returned by operator[]
with a class called reference
, just as std::bitset<>
does. So, that is useful because in my wrapper -- that is templated with the bitset type BITSET
-- I can then do
typename BITSET::reference operator[](INDEX_TYPE i)
{ return bitset[i]; }
and it will work for both, std::bitset<>
and boost::dynamic_bitset<>
.
However, there are features that are not parallelized like that. For instance declares boost::dynamic_bitset<>
typedef std::size_t size_type;
as the index type, as in:
bool operator[](size_type pos) const { return test(pos); }
But std::bitset<>
simply uses size_t
for that:
_GLIBCXX_CONSTEXPR bool
operator[](size_t __position) const
{ return _Unchecked_test(__position); }
So, in my Wrapper I could do typedef size_t INDEX_TYPE
or something like that, but that might not work for another implementation that does not use size_t
, as these two coincidentally (or not) do.
Obviously there is no really generic way to do this, but could I at least somehow conditionally define my INDEX_TYPE
, akin to this:
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());
The above approach does not work and even if it did looks very clunky.
It is besides the point of my question, but just for completeness this is the error:
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
I guess you can't just put conditionals randomly into the class space outside of functions, and this was the first time I ever tried this, because of the weird circumstances.
But how can this be approached correctly?
You cannot use if/else
logic to defined a typedef
like that. You can use a helper class to deduce it.
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;
};
And then use:
template <class BITSET, class T>
class BitsetWrapper
{
using INDEX_TYPE = typename TypedefSelector<T>::IndexType;
...
};
For typenames that don't have a TypedefSelector
, you will get compile time error.